summaryrefslogtreecommitdiff
path: root/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509
diff options
context:
space:
mode:
Diffstat (limited to 'linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509')
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/1764-1.patch16
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch326
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-2.4.18-mh15.patch32759
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff30831
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/cacko.patch0
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/defconfig-collie1283
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch17
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch77
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch14
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff399
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff1513
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff838
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch19
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch2598
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch16
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/module_licence.patch81
-rw-r--r--linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch5602
17 files changed, 0 insertions, 76389 deletions
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/1764-1.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/1764-1.patch
deleted file mode 100644
index 0b660f3521..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/1764-1.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-__arch_strncpy_from_user needs to be exported if you build the framebuffer console driver as a module.
-
-Cheers,
-
-Ian.
-
---- linux-2.6-bkpxa.orig/arch/arm/kernel/armksyms.c 2004-02-27 10:35:29.000000000 +0000
-+++ linux-2.6-bkpxa/arch/arm/kernel/armksyms.c 2004-02-27 14:55:02.000000000 +0000
-@@ -187,6 +187,7 @@
- EXPORT_SYMBOL(__arch_copy_to_user);
- EXPORT_SYMBOL(__arch_clear_user);
- EXPORT_SYMBOL(__arch_strnlen_user);
-+EXPORT_SYMBOL(__arch_strncpy_from_user);
-
- /* consistent area handling */
- EXPORT_SYMBOL(consistent_alloc);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch
deleted file mode 100644
index 1912b33328..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch
+++ /dev/null
@@ -1,326 +0,0 @@
-
---- linux/arch/arm/mach-sa1100/collie_battery.c Tue Jul 22 02:24:32 2003
-+++ linux/arch/arm/mach-sa1100/collie_battery.c Tue Jul 22 03:07:56 2003
-@@ -14,10 +14,11 @@
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * ChangeLog:
-+ * Nov 2002 Dietz Proepper: improved battery status.
- * 12-Nov-2001 Lineo Japan, Inc.
- * 30-Jul-2002 Lineo Japan, Inc. for 2.4.18
- * 29-Jan-2003 Sharp Corporation modify for new QT I/F
- *
- */
-@@ -79,10 +80,11 @@ int collie_read_BackBattery(void);
- int collie_read_Temp(void);
- int collie_check_temp(void);
- int collie_check_voltage(void);
- static void collie_charge_on(void);
- static void collie_charge_off(void);
-+static void do_main_battery(void);
- int set_led_status(int which,int status);
- int GetMainLevel( int Volt );
- int GetBackLevel( int Volt );
- int collie_get_main_battery(void);
- unsigned short GetBackupBatteryAD(void);
-@@ -91,40 +93,35 @@ int suspend_collie_read_Temp(void);
- /*** extern ***********************************************************************/
- extern u32 apm_wakeup_src_mask;
- extern int counter_step_contrast;
-
-
--/*** gloabal variables ************************************************************/
--int charge_status = 0; /* charge status 1 : charge 0: not charge */
--
--typedef struct BatteryThresh {
-- int high;
-- int low;
-- int verylow;
--} BATTERY_THRESH;
-+/* defines */
-+#define COLLIE_BATTERY_STATUS_HIGH APM_BATTERY_STATUS_HIGH
-+#define COLLIE_BATTERY_STATUS_LOW APM_BATTERY_STATUS_LOW
-+#define COLLIE_BATTERY_STATUS_VERYLOW APM_BATTERY_STATUS_VERY_LOW
-+#define COLLIE_BATTERY_STATUS_CRITICAL APM_BATTERY_STATUS_CRITICAL
-
-+/*** gloabal variables ************************************************************/
-+int charge_status = 0; /* charge status 1 : charge 0: not charge */
-
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
-- defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
--BATTERY_THRESH collie_main_battery_thresh_fl = {
-- 368, 358, 356
--};
--
--BATTERY_THRESH collie_main_battery_thresh_nofl = {
-- 378, 364, 362
--};
--#else
--BATTERY_THRESH collie_main_battery_thresh_fl = {
-- 368, 358, 356
--};
--
--BATTERY_THRESH collie_main_battery_thresh_nofl = {
-- 378, 365, 363
-+typedef struct {
-+ int voltage_thres[2]; /* 0: nofl 1: fl */
-+ int percent;
-+ int state;
-+} main_battery_thres;
-+
-+#define MAIN_BATTERY_THRES 4
-+
-+main_battery_thres main_batt_thres[MAIN_BATTERY_THRES+2] = {
-+ {{5000, 5000}, 100, COLLIE_BATTERY_STATUS_HIGH }, /* do not remove! */
-+ {{412,408}, 100, COLLIE_BATTERY_STATUS_HIGH},
-+ {{378,368}, 40, COLLIE_BATTERY_STATUS_HIGH},
-+ {{364,358}, 5, COLLIE_BATTERY_STATUS_LOW},
-+ {{362,356}, 1, COLLIE_BATTERY_STATUS_CRITICAL},
-+ {{0, 0}, 1, COLLIE_BATTERY_STATUS_CRITICAL } /* do not remove, too! */
- };
--#endif
--
--
-
- typedef struct ChargeThresh {
- int bar1;
- int bar2;
- int bar3;
-@@ -180,24 +177,18 @@ static struct miscdevice battery_device
- #define GetBackADCtoPower(x) (( 330 * x * 2 ) / 1024 ) // MAX 3.3V
- #define ConvRevise(x) ( ( ad_revise * x ) / 652 )
- #define MAIN_DIFF 50 // 0.5V
- #define DIFF_CNT ( 3 - 1 )
-
--#define COLLIE_BATTERY_STATUS_HIGH APM_BATTERY_STATUS_HIGH
--#define COLLIE_BATTERY_STATUS_LOW APM_BATTERY_STATUS_LOW
--#define COLLIE_BATTERY_STATUS_VERYLOW APM_BATTERY_STATUS_VERY_LOW
--#define COLLIE_BATTERY_STATUS_CRITICAL APM_BATTERY_STATUS_CRITICAL
--
- #define COLLIE_AC_LINE_STATUS (!( GPLR & GPIO_AC_IN ) ? APM_AC_OFFLINE : APM_AC_ONLINE)
-
--
- #define COLLIE_PM_TICK ( 1000 / 10 ) // 1sec
- #define COLLIE_APO_TICKTIME ( 5 * COLLIE_PM_TICK ) // 5sec
- #define COLLIE_LPO_TICKTIME COLLIE_APO_TICKTIME
- #define COLLIE_APO_DEFAULT ( ( 3 * 60 ) * COLLIE_PM_TICK ) // 3 min
- #define COLLIE_LPO_DEFAULT ( 20 * COLLIE_PM_TICK ) // 20 sec
--#define COLLIE_MAIN_GOOD_COUNT ( 10*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
-+#define COLLIE_MAIN_GOOD_COUNT ( 1*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
- #define COLLIE_MAIN_NOGOOD_COUNT ( 1*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
-
- #define COLLIE_BACKUP_BATTERY_CK_TIME ( 10*60*1*100 ) // 10min
- #define COLLIE_BACKUP_BATTERY_LOW ( 190 )
-
-@@ -212,10 +203,11 @@ unsigned int LPOCntWk = 0;
- static DECLARE_WAIT_QUEUE_HEAD(queue);
- static int msglevel;
-
- int collie_backup_battery = COLLIE_BATTERY_STATUS_HIGH;
- int collie_main_battery = COLLIE_BATTERY_STATUS_HIGH;
-+int collie_main_battery_percent = 100;
- int collie_main_charge_battery = 100;
- int collie_ac_status = APM_AC_OFFLINE;
- int ad_revise = 0;
-
- static int MainCntWk = COLLIE_MAIN_GOOD_COUNT;
-@@ -229,10 +221,11 @@ static struct pm_dev *battery_pm_dev; /
-
- static int battery_off_flag = 0; /* charge : suspend while get adc */
- static int collie_charge_temp = 973;
- static int collie_charge_volt = 465; /* charge : check charge 3.0V */
- static int charge_off_mode = 0; /* charge : check volt or non */
-+static int collie_main_battery_voltage = 400;
-
- static DECLARE_WAIT_QUEUE_HEAD(wq_on);
- static DECLARE_WAIT_QUEUE_HEAD(wq_off);
- #if 1 // 2003.1.29
- static DECLARE_WAIT_QUEUE_HEAD(battery_waitqueue);
-@@ -276,28 +269,11 @@ int collie_apm_get_power_status(u_char *
- }
- collie_battery_status = *battery_status;
- #endif
-
- // main battery status to percentage
-- switch (*battery_status)
-- {
-- case COLLIE_BATTERY_STATUS_HIGH:
-- *battery_percentage = 100;
-- break;
-- case COLLIE_BATTERY_STATUS_LOW:
-- *battery_percentage = 40;
-- break;
-- case COLLIE_BATTERY_STATUS_VERYLOW:
-- *battery_percentage = 5;
-- break;
-- case COLLIE_BATTERY_STATUS_CRITICAL:
-- *battery_percentage = 1;
-- break;
-- default:
-- *battery_percentage = 100;
-- break;
-- }
-+ *battery_percentage = collie_main_battery_percent;
-
- if ( *ac_line_status == APM_AC_ONLINE )
- *battery_percentage = 100;
-
- // good or ac in --> GOOD_COUNT
-@@ -529,12 +505,13 @@ int collie_get_main_battery(void)
- voltage = collie_read_MainBattery();
- if ( voltage > 0 ) break;
- if ( i++ > 5 ) { voltage = 380; break; }
- }
-
-- collie_main_battery = GetMainLevel(GetMainADCtoPower(voltage));
-- collie_main_charge_battery = GetMainChargePercent(GetMainADCtoPower(voltage));
-+ collie_main_battery_voltage = GetMainADCtoPower(voltage);
-+ do_main_battery();
-+ collie_main_charge_battery = GetMainChargePercent(collie_main_battery_voltage);
-
- DPRINTK2("charge percent = %d ( at %d ) \n",collie_main_charge_battery,jiffies);
-
- DPRINTK(" get Main battery status %d\n",collie_main_battery);
-
-@@ -562,36 +539,36 @@ int GetMainChargePercent( int Volt )
- } else {
- return 5;
- }
- }
-
--int GetMainLevel( int Volt )
-+static void do_main_battery()
- {
--
-- DPRINTK(" volt = %d \n",Volt);
--
--
-- if ( counter_step_contrast ) {
-- if ( Volt > collie_main_battery_thresh_fl.high )
-- return COLLIE_BATTERY_STATUS_HIGH;
-- else if ( Volt > collie_main_battery_thresh_fl.low )
-- return COLLIE_BATTERY_STATUS_LOW;
-- else if ( Volt > collie_main_battery_thresh_fl.verylow )
-- return COLLIE_BATTERY_STATUS_VERYLOW;
-- else
-- return COLLIE_BATTERY_STATUS_CRITICAL;
-- } else {
-- if ( Volt > collie_main_battery_thresh_nofl.high )
-- return COLLIE_BATTERY_STATUS_HIGH;
-- else if ( Volt > collie_main_battery_thresh_nofl.low )
-- return COLLIE_BATTERY_STATUS_LOW;
-- else if ( Volt > collie_main_battery_thresh_nofl.verylow )
-- return COLLIE_BATTERY_STATUS_VERYLOW;
-- else
-- return COLLIE_BATTERY_STATUS_CRITICAL;
-- }
--
-+ int i = MAIN_BATTERY_THRES;
-+ int fl = (counter_step_contrast)? 1 : 0;
-+
-+ while ( i > 0 &&
-+ ( collie_main_battery_voltage > main_batt_thres[i].voltage_thres[fl] ) )
-+ i--;
-+ /* i is now between 0 and MAIN_BATTERY_THRES. That means
-+ * we can safely access main_batt_thres[i] and
-+ * main_batt_thres[i+1] */
-+
-+ collie_main_battery = main_batt_thres[i].state;
-+ { /* perhaps we should put that deltas to our table, too? */
-+ long deltav = main_batt_thres[i].voltage_thres[fl] -
-+ main_batt_thres[i+1].voltage_thres[fl];
-+ long deltap = main_batt_thres[i].percent -
-+ main_batt_thres[i+1].percent;
-+
-+ collie_main_battery_percent = /* (1) */
-+ main_batt_thres[i+1].percent +
-+ deltap * (collie_main_battery_voltage -
-+ main_batt_thres[i+1].voltage_thres[fl]) /
-+ deltav;
-+ DPRINTK("Battery stuff: v=%i i=%i , dv=%li , dp=%li , p=%i",collie_main_battery_voltage , i, deltav, deltap, collie_main_battery_percent );
-+ }
- }
-
-
- int GetBackLevel( int Volt )
- {
-@@ -834,20 +811,18 @@ unsigned short chkFatalBatt(void)
- GEDR = GPIO_CO;
- // printk("CO = %x\n",GEDR&GPIO_CO);
- }
-
-
-- if ( volt < collie_main_battery_thresh_nofl.verylow )
-+ if ( volt < main_batt_thres[MAIN_BATTERY_THRES].voltage_thres[0] )
- return 0;
- else
- return 1;
- #endif
- }
-
-
--
--
- int suspend_collie_check_temp(void)
- {
- unsigned short temp , i = 0;
-
- while(1) {
-@@ -1032,10 +1007,11 @@ struct proc_dir_entry *proc_batt;
- typedef struct collie_battery_entry {
- int* addr;
- int def_value;
- char* name;
- char* description;
-+ char readonly;
- unsigned short low_ino;
- } collie_battery_entry_t;
-
- #if 1 // 2003.1.29
- static collie_battery_entry_t collie_battery_params[] = {
-@@ -1044,11 +1020,13 @@ static collie_battery_entry_t collie_bat
- { &collie_change_battery_status , 0 , "chg_status", "Change status" }
- };
- #else
- static collie_battery_entry_t collie_battery_params[] = {
- /* { addr, def_value, name, description }*/
-- { &msglevel, 0, "msglevel", "debug message output level" }
-+/* { &msglevel, 0, "msglevel", "debug message output level" } */
-+ { &msglevel, 0, "msglevel", "debug message output level", 0 },
-+ { &collie_main_battery_voltage, -1, "main_voltage", "main battery voltage", 1 }
- };
- #endif
- #define NUM_OF_BATTERY_ENTRY (sizeof(collie_battery_params)/sizeof(collie_battery_entry_t))
-
- static ssize_t collie_battery_read_params(struct file *file, char *buf,
-@@ -1069,11 +1047,12 @@ static ssize_t collie_battery_read_param
- }
- }
- if (current_param==NULL) {
- return -EINVAL;
- }
-- count = sprintf(outputbuf, "0x%08X\n",
-+// count = sprintf(outputbuf, "0x%08X\n",
-+ count = sprintf(outputbuf, "%04i\n",
- *((volatile Word *) current_param->addr));
- *ppos += count;
- if (count>nbytes) /* Assume output can be read at one time */
- return -EINVAL;
- if (copy_to_user(buf, outputbuf, count))
-@@ -1094,11 +1073,12 @@ static ssize_t collie_battery_write_para
- if(collie_battery_params[i].low_ino==i_ino) {
- current_param = &collie_battery_params[i];
- break;
- }
- }
-- if (current_param==NULL) {
-+// if (current_param==NULL) {
-+ if (current_param==NULL || current_param->readonly) {
- return -EINVAL;
- }
-
- param = simple_strtoul(buf,&endp,0);
- if (param == -1) {
-
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-2.4.18-mh15.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-2.4.18-mh15.patch
deleted file mode 100644
index 1a7fd98653..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-2.4.18-mh15.patch
+++ /dev/null
@@ -1,32759 +0,0 @@
-diff -urN linux-2.4.18/arch/alpha/config.in linux-2.4.18-mh15/arch/alpha/config.in
---- linux-2.4.18/arch/alpha/config.in 2001-11-21 00:49:31.000000000 +0100
-+++ linux-2.4.18-mh15/arch/alpha/config.in 2004-08-01 16:26:22.000000000 +0200
-@@ -371,9 +371,7 @@
- source drivers/usb/Config.in
- source drivers/input/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/arm/config.in linux-2.4.18-mh15/arch/arm/config.in
---- linux-2.4.18/arch/arm/config.in 2001-11-09 22:58:02.000000000 +0100
-+++ linux-2.4.18-mh15/arch/arm/config.in 2004-08-01 16:26:22.000000000 +0200
-@@ -584,9 +584,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/i386/config.in linux-2.4.18-mh15/arch/i386/config.in
---- linux-2.4.18/arch/i386/config.in 2002-02-25 20:37:52.000000000 +0100
-+++ linux-2.4.18-mh15/arch/i386/config.in 2004-08-01 16:26:22.000000000 +0200
-@@ -407,9 +407,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/ppc/config.in linux-2.4.18-mh15/arch/ppc/config.in
---- linux-2.4.18/arch/ppc/config.in 2002-02-25 20:37:55.000000000 +0100
-+++ linux-2.4.18-mh15/arch/ppc/config.in 2004-08-01 16:26:22.000000000 +0200
-@@ -389,9 +389,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/sparc/config.in linux-2.4.18-mh15/arch/sparc/config.in
---- linux-2.4.18/arch/sparc/config.in 2001-06-12 04:15:27.000000000 +0200
-+++ linux-2.4.18-mh15/arch/sparc/config.in 2004-08-01 16:26:22.000000000 +0200
-@@ -251,9 +251,7 @@
-
- source fs/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Watchdog'
-diff -urN linux-2.4.18/arch/sparc64/config.in linux-2.4.18-mh15/arch/sparc64/config.in
---- linux-2.4.18/arch/sparc64/config.in 2001-12-21 18:41:53.000000000 +0100
-+++ linux-2.4.18-mh15/arch/sparc64/config.in 2004-08-01 16:26:22.000000000 +0200
-@@ -283,9 +283,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Watchdog'
-diff -urN linux-2.4.18/arch/sparc64/kernel/ioctl32.c linux-2.4.18-mh15/arch/sparc64/kernel/ioctl32.c
---- linux-2.4.18/arch/sparc64/kernel/ioctl32.c 2002-02-25 20:37:56.000000000 +0100
-+++ linux-2.4.18-mh15/arch/sparc64/kernel/ioctl32.c 2004-08-01 16:26:23.000000000 +0200
-@@ -92,6 +92,7 @@
-
- #include <net/bluetooth/bluetooth.h>
- #include <net/bluetooth/hci.h>
-+#include <net/bluetooth/rfcomm.h>
-
- #include <linux/usb.h>
- #include <linux/usbdevice_fs.h>
-@@ -3822,6 +3823,15 @@
- return err;
- }
-
-+/* Bluetooth ioctls */
-+#define HCIUARTSETPROTO _IOW('U', 200, int)
-+#define HCIUARTGETPROTO _IOR('U', 201, int)
-+
-+#define BNEPCONNADD _IOW('B', 200, int)
-+#define BNEPCONNDEL _IOW('B', 201, int)
-+#define BNEPGETCONNLIST _IOR('B', 210, int)
-+#define BNEPGETCONNINFO _IOR('B', 211, int)
-+
- struct mtd_oob_buf32 {
- u32 start;
- u32 length;
-@@ -3878,6 +3888,16 @@
- return ((0 == ret) ? 0 : -EFAULT);
- }
-
-+#define CMTPCONNADD _IOW('C', 200, int)
-+#define CMTPCONNDEL _IOW('C', 201, int)
-+#define CMTPGETCONNLIST _IOR('C', 210, int)
-+#define CMTPGETCONNINFO _IOR('C', 211, int)
-+
-+#define HIDPCONNADD _IOW('H', 200, int)
-+#define HIDPCONNDEL _IOW('H', 201, int)
-+#define HIDPGETCONNLIST _IOR('H', 210, int)
-+#define HIDPGETCONNINFO _IOR('H', 211, int)
-+
- struct ioctl_trans {
- unsigned int cmd;
- unsigned int handler;
-@@ -4540,6 +4560,25 @@
- COMPATIBLE_IOCTL(HCISETSCAN)
- COMPATIBLE_IOCTL(HCISETAUTH)
- COMPATIBLE_IOCTL(HCIINQUIRY)
-+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
-+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
-+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
-+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
-+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
-+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
-+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-+COMPATIBLE_IOCTL(BNEPCONNADD)
-+COMPATIBLE_IOCTL(BNEPCONNDEL)
-+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
-+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-+COMPATIBLE_IOCTL(CMTPCONNADD)
-+COMPATIBLE_IOCTL(CMTPCONNDEL)
-+COMPATIBLE_IOCTL(CMTPGETCONNLIST)
-+COMPATIBLE_IOCTL(CMTPGETCONNINFO)
-+COMPATIBLE_IOCTL(HIDPCONNADD)
-+COMPATIBLE_IOCTL(HIDPCONNDEL)
-+COMPATIBLE_IOCTL(HIDPGETCONNLIST)
-+COMPATIBLE_IOCTL(HIDPGETCONNINFO)
- /* Misc. */
- COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */
- COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */
-diff -urN linux-2.4.18/CREDITS linux-2.4.18-mh15/CREDITS
---- linux-2.4.18/CREDITS 2002-02-25 20:37:50.000000000 +0100
-+++ linux-2.4.18-mh15/CREDITS 2004-08-01 16:26:23.000000000 +0200
-@@ -1317,6 +1317,16 @@
- S: Provo, Utah 84606-5607
- S: USA
-
-+N: Marcel Holtmann
-+E: marcel@holtmann.org
-+W: http://www.holtmann.org
-+D: Maintainer of the Linux Bluetooth Subsystem
-+D: Author and maintainer of the various Bluetooth HCI drivers
-+D: Author and maintainer of the CAPI message transport protocol driver
-+D: Author and maintainer of the Bluetooth HID protocol driver
-+D: Various other Bluetooth related patches, cleanups and fixes
-+S: Germany
-+
- N: Rob W. W. Hooft
- E: hooft@EMBL-Heidelberg.DE
- D: Shared libs for graphics-tools and for the f2c compiler
-@@ -2546,6 +2556,7 @@
- N: Aristeu Sergio Rozanski Filho
- E: aris@conectiva.com.br
- D: Support for EtherExpress 10 ISA (i82595) in eepro driver
-+D: User level driver support for input
- S: Conectiva S.A.
- S: R. Tocantins, 89 - Cristo Rei
- S: 80050-430 - Curitiba - Paraná
-diff -urN linux-2.4.18/Documentation/Configure.help linux-2.4.18-mh15/Documentation/Configure.help
---- linux-2.4.18/Documentation/Configure.help 2002-02-25 20:37:51.000000000 +0100
-+++ linux-2.4.18-mh15/Documentation/Configure.help 2004-08-01 16:26:23.000000000 +0200
-@@ -2824,14 +2824,6 @@
-
- If unsure, say N.
-
--HCI EMU (virtual device) driver
--CONFIG_BLUEZ_HCIEMU
-- Bluetooth Virtual HCI device driver.
-- This driver is required if you want to use HCI Emulation software.
--
-- Say Y here to compile support for Virtual HCI devices into the
-- kernel or say M to compile it as module (hci_usb.o).
--
- # Choice: alphatype
- Alpha system type
- CONFIG_ALPHA_GENERIC
-@@ -11037,6 +11029,12 @@
-
- If unsure, say N.
-
-+Hotplug firmware loading support (EXPERIMENTAL)
-+CONFIG_FW_LOADER
-+ This option is provided for the case where no in-kernel-tree modules require
-+ hotplug firmware loading support, but a module built outside the kernel tree
-+ does.
-+
- Use PCI shared memory for NIC registers
- CONFIG_TULIP_MMIO
- Use PCI shared memory for the NIC registers, rather than going through
-@@ -12896,6 +12894,15 @@
- accessible under char device 13:64+ - /dev/input/eventX in a generic
- way. This is the future ...
-
-+CONFIG_INPUT_UINPUT
-+ Say Y here if you want to support user level drivers for input
-+ subsystem accessible under char device 10:223 - /dev/input/uinput.
-+
-+ This driver is also available as a module ( = code which can be
-+ inserted in and removed from the running kernel whenever you want).
-+ The module will be called uinput.o. If you want to compile it as a
-+ module, say M here and read <file:Documentation/modules.txt>.
-+
- USB Scanner support
- CONFIG_USB_SCANNER
- Say Y here if you want to connect a USB scanner to your computer's
-@@ -19870,19 +19877,22 @@
- Bluetooth can be found at <http://www.bluetooth.com/>.
-
- Linux Bluetooth subsystem consist of several layers:
-- HCI Core (device and connection manager, scheduler)
-- HCI Device drivers (interface to the hardware)
-- L2CAP Module (L2CAP protocol)
-+ BlueZ Core (HCI device and connection manager, scheduler)
-+ HCI Device drivers (Interface to the hardware)
-+ SCO Module (SCO audio links)
-+ L2CAP Module (Logical Link Control and Adaptation Protocol)
-+ RFCOMM Module (RFCOMM Protocol)
-+ BNEP Module (Bluetooth Network Encapsulation Protocol)
-+ CMTP Module (CAPI Message Transport Protocol)
-+ HIDP Module (Human Interface Device Protocol)
-
-- Say Y here to enable Linux Bluetooth support and to build HCI Core
-- layer.
-+ Say Y here to compile Bluetooth support into the kernel or say M to
-+ compile it as module (bluez.o).
-
- To use Linux Bluetooth subsystem, you will need several user-space
- utilities like hciconfig and hcid. These utilities and updates to
- Bluetooth kernel modules are provided in the BlueZ package.
-- For more information, see <http://bluez.sourceforge.net/>.
--
-- If you want to compile HCI Core as module (hci.o) say M here.
-+ For more information, see <http://www.bluez.org/>.
-
- L2CAP protocol support
- CONFIG_BLUEZ_L2CAP
-@@ -19893,15 +19903,96 @@
- Say Y here to compile L2CAP support into the kernel or say M to
- compile it as module (l2cap.o).
-
-+SCO links support
-+CONFIG_BLUEZ_SCO
-+ SCO link provides voice transport over Bluetooth. SCO support is
-+ required for voice applications like Headset and Audio.
-+
-+ Say Y here to compile SCO support into the kernel or say M to
-+ compile it as module (sco.o).
-+
-+RFCOMM protocol support
-+CONFIG_BLUEZ_RFCOMM
-+ RFCOMM provides connection oriented stream transport. RFCOMM
-+ support is required for Dialup Networking, OBEX and other Bluetooth
-+ applications.
-+
-+ Say Y here to compile RFCOMM support into the kernel or say M to
-+ compile it as module (rfcomm.o).
-+
-+RFCOMM TTY emulation support
-+CONFIG_BLUEZ_RFCOMM_TTY
-+ This option enables TTY emulation support for RFCOMM channels.
-+
-+BNEP protocol support
-+CONFIG_BLUEZ_BNEP
-+ BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
-+ emulation layer on top of Bluetooth. BNEP is required for
-+ Bluetooth PAN (Personal Area Network).
-+
-+ Say Y here to compile BNEP support into the kernel or say M to
-+ compile it as module (bnep.o).
-+
-+BNEP multicast filter support
-+CONFIG_BLUEZ_BNEP_MC_FILTER
-+ This option enables the multicast filter support for BNEP.
-+
-+BNEP protocol filter support
-+CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ This option enables the protocol filter support for BNEP.
-+
-+CMTP protocol support
-+CONFIG_BLUEZ_CMTP
-+ CMTP (CAPI Message Transport Protocol) is a transport layer
-+ for CAPI messages. CMTP is required for the Bluetooth Common
-+ ISDN Access Profile.
-+
-+ Say Y here to compile CMTP support into the kernel or say M to
-+ compile it as module (cmtp.o).
-+
-+HIDP protocol support
-+CONFIG_BLUEZ_HIDP
-+ HIDP (Human Interface Device Protocol) is a transport layer
-+ for HID reports. HIDP is required for the Bluetooth Human
-+ Interface Device Profile.
-+
-+ Say Y here to compile HIDP support into the kernel or say M to
-+ compile it as module (hidp.o).
-+
- HCI UART driver
- CONFIG_BLUEZ_HCIUART
- Bluetooth HCI UART driver.
- This driver is required if you want to use Bluetooth devices with
-- serial port interface.
-+ serial port interface. You will also need this driver if you have
-+ UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
-+ adapter and BrainBoxes Bluetooth PC Card.
-
- Say Y here to compile support for Bluetooth UART devices into the
- kernel or say M to compile it as module (hci_uart.o).
-
-+HCI UART (H4) protocol support
-+CONFIG_BLUEZ_HCIUART_H4
-+ UART (H4) is serial protocol for communication between Bluetooth
-+ device and host. This protocol is required for most Bluetooth devices
-+ with UART interface, including PCMCIA and CF cards.
-+
-+ Say Y here to compile support for HCI UART (H4) protocol.
-+
-+HCI BCSP protocol support
-+CONFIG_BLUEZ_HCIUART_BCSP
-+ BCSP (BlueCore Serial Protocol) is serial protocol for communication
-+ between Bluetooth device and host. This protocol is required for non
-+ USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and
-+ CF cards.
-+
-+ Say Y here to compile support for HCI BCSP protocol.
-+
-+HCI BCSP transmit CRC with every BCSP packet
-+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ If you say Y here, a 16-bit CRC checksum will be transmitted along with
-+ every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
-+ This increases reliability, but slightly reduces efficiency.
-+
- HCI USB driver
- CONFIG_BLUEZ_HCIUSB
- Bluetooth HCI USB driver.
-@@ -19911,7 +20002,16 @@
- Say Y here to compile support for Bluetooth USB devices into the
- kernel or say M to compile it as module (hci_usb.o).
-
--HCI VHCI virtual HCI device driver
-+HCI USB SCO (voice) support
-+CONFIG_BLUEZ_HCIUSB_SCO
-+ This option enables the SCO support in the HCI USB driver. You need this
-+ to transmit voice data with your Bluetooth USB device. And your device
-+ must also support sending SCO data over the HCI layer, because some of
-+ them sends the SCO data to an internal PCM adapter.
-+
-+ Say Y here to compile support for HCI SCO data.
-+
-+HCI VHCI Virtual HCI device driver
- CONFIG_BLUEZ_HCIVHCI
- Bluetooth Virtual HCI device driver.
- This driver is required if you want to use HCI Emulation software.
-@@ -19919,6 +20019,63 @@
- Say Y here to compile support for virtual HCI devices into the
- kernel or say M to compile it as module (hci_vhci.o).
-
-+HCI BFUSB device driver
-+CONFIG_BLUEZ_HCIBFUSB
-+ Bluetooth HCI BlueFRITZ! USB driver.
-+ This driver provides support for Bluetooth USB devices with AVM
-+ interface:
-+ AVM BlueFRITZ! USB
-+
-+ Say Y here to compile support for HCI BFUSB devices into the
-+ kernel or say M to compile it as module (bfusb.o).
-+
-+HCI DTL1 (PC Card) device driver
-+CONFIG_BLUEZ_HCIDTL1
-+ Bluetooth HCI DTL1 (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ Nokia DTL1 interface:
-+ Nokia Bluetooth Card
-+ Socket Bluetooth CF Card
-+
-+ Say Y here to compile support for HCI DTL1 devices into the
-+ kernel or say M to compile it as module (dtl1_cs.o).
-+
-+HCI BT3C (PC Card) device driver
-+CONFIG_BLUEZ_HCIBT3C
-+ Bluetooth HCI BT3C (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ 3Com BT3C interface:
-+ 3Com Bluetooth Card (3CRWB6096)
-+ HP Bluetooth Card
-+
-+ Say Y here to compile support for HCI BT3C devices into the
-+ kernel or say M to compile it as module (bt3c_cs.o).
-+
-+HCI BlueCard (PC Card) device driver
-+CONFIG_BLUEZ_HCIBLUECARD
-+ Bluetooth HCI BlueCard (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ Anycom BlueCard interface:
-+ Anycom Bluetooth PC Card
-+ Anycom Bluetooth CF Card
-+
-+ Say Y here to compile support for HCI BlueCard devices into the
-+ kernel or say M to compile it as module (bluecard_cs.o).
-+
-+HCI UART (PC Card) device driver
-+CONFIG_BLUEZ_HCIBTUART
-+ Bluetooth HCI UART (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ an UART interface:
-+ Xircom CreditCard Bluetooth Adapter
-+ Xircom RealPort2 Bluetooth Adapter
-+ Sphinx PICO Card
-+ H-Soft blue+Card
-+ Cyber-blue Compact Flash Card
-+
-+ Say Y here to compile support for HCI UART devices into the
-+ kernel or say M to compile it as module (btuart_cs.o).
-+
- # The following options are for Linux when running on the Hitachi
- # SuperH family of RISC microprocessors.
-
-diff -urN linux-2.4.18/Documentation/devices.txt linux-2.4.18-mh15/Documentation/devices.txt
---- linux-2.4.18/Documentation/devices.txt 2001-11-07 23:46:01.000000000 +0100
-+++ linux-2.4.18-mh15/Documentation/devices.txt 2004-08-01 16:26:23.000000000 +0200
-@@ -419,6 +419,7 @@
- 220 = /dev/mptctl Message passing technology (MPT) control
- 221 = /dev/mvista/hssdsi Montavista PICMG hot swap system driver
- 222 = /dev/mvista/hasi Montavista PICMG high availability
-+ 223 = /dev/input/uinput User level driver support for input
- 240-255 Reserved for local use
-
- 11 char Raw keyboard device
-diff -urN linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c linux-2.4.18-mh15/Documentation/firmware_class/firmware_sample_driver.c
---- linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/Documentation/firmware_class/firmware_sample_driver.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,121 @@
-+/*
-+ * firmware_sample_driver.c -
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Sample code on how to use request_firmware() from drivers.
-+ *
-+ * Note that register_firmware() is currently useless.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/string.h>
-+
-+#include "linux/firmware.h"
-+
-+#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+char __init inkernel_firmware[] = "let's say that this is firmware\n";
-+#endif
-+
-+static char ghost_device[] = "ghost0";
-+
-+static void sample_firmware_load(char *firmware, int size)
-+{
-+ u8 buf[size+1];
-+ memcpy(buf, firmware, size);
-+ buf[size] = '\0';
-+ printk("firmware_sample_driver: firmware: %s\n", buf);
-+}
-+
-+static void sample_probe_default(void)
-+{
-+ /* uses the default method to get the firmware */
-+ const struct firmware *fw_entry;
-+ printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+ if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0)
-+ {
-+ printk(KERN_ERR
-+ "firmware_sample_driver: Firmware not available\n");
-+ return;
-+ }
-+
-+ sample_firmware_load(fw_entry->data, fw_entry->size);
-+
-+ release_firmware(fw_entry);
-+
-+ /* finish setting up the device */
-+}
-+static void sample_probe_specific(void)
-+{
-+ /* Uses some specific hotplug support to get the firmware from
-+ * userspace directly into the hardware, or via some sysfs file */
-+
-+ /* NOTE: This currently doesn't work */
-+
-+ printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+ if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0)
-+ {
-+ printk(KERN_ERR
-+ "firmware_sample_driver: Firmware load failed\n");
-+ return;
-+ }
-+
-+ /* request_firmware blocks until userspace finished, so at
-+ * this point the firmware should be already in the device */
-+
-+ /* finish setting up the device */
-+}
-+static void sample_probe_async_cont(const struct firmware *fw, void *context)
-+{
-+ if(!fw){
-+ printk(KERN_ERR
-+ "firmware_sample_driver: firmware load failed\n");
-+ return;
-+ }
-+
-+ printk("firmware_sample_driver: device pointer \"%s\"\n",
-+ (char *)context);
-+ sample_firmware_load(fw->data, fw->size);
-+}
-+static void sample_probe_async(void)
-+{
-+ /* Let's say that I can't sleep */
-+ int error;
-+ error = request_firmware_nowait (THIS_MODULE,
-+ "sample_driver_fw", ghost_device,
-+ "my device pointer",
-+ sample_probe_async_cont);
-+ if(error){
-+ printk(KERN_ERR
-+ "firmware_sample_driver:"
-+ " request_firmware_nowait failed\n");
-+ }
-+}
-+
-+static int sample_init(void)
-+{
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+ register_firmware("sample_driver_fw", inkernel_firmware,
-+ sizeof(inkernel_firmware));
-+#endif
-+ /* since there is no real hardware insertion I just call the
-+ * sample probe functions here */
-+ sample_probe_specific();
-+ sample_probe_default();
-+ sample_probe_async();
-+ return 0;
-+}
-+static void __exit sample_exit(void)
-+{
-+}
-+
-+module_init (sample_init);
-+module_exit (sample_exit);
-+
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/Documentation/firmware_class/hotplug-script linux-2.4.18-mh15/Documentation/firmware_class/hotplug-script
---- linux-2.4.18/Documentation/firmware_class/hotplug-script 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/Documentation/firmware_class/hotplug-script 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,16 @@
-+#!/bin/sh
-+
-+# Simple hotplug script sample:
-+#
-+# Both $DEVPATH and $FIRMWARE are already provided in the environment.
-+
-+HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
-+
-+echo 1 > /sysfs/$DEVPATH/loading
-+cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
-+echo 0 > /sysfs/$DEVPATH/loading
-+
-+# To cancel the load in case of error:
-+#
-+# echo -1 > /sysfs/$DEVPATH/loading
-+#
-diff -urN linux-2.4.18/Documentation/firmware_class/README linux-2.4.18-mh15/Documentation/firmware_class/README
---- linux-2.4.18/Documentation/firmware_class/README 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/Documentation/firmware_class/README 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,58 @@
-+
-+ request_firmware() hotplug interface:
-+ ------------------------------------
-+ Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+
-+ Why:
-+ ---
-+
-+ Today, the most extended way to use firmware in the Linux kernel is linking
-+ it statically in a header file. Which has political and technical issues:
-+
-+ 1) Some firmware is not legal to redistribute.
-+ 2) The firmware occupies memory permanently, even though it often is just
-+ used once.
-+ 3) Some people, like the Debian crowd, don't consider some firmware free
-+ enough and remove entire drivers (e.g.: keyspan).
-+
-+ about in-kernel persistence:
-+ ---------------------------
-+ Under some circumstances, as explained below, it would be interesting to keep
-+ firmware images in non-swappable kernel memory or even in the kernel image
-+ (probably within initramfs).
-+
-+ Note that this functionality has not been implemented.
-+
-+ - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
-+
-+ - If the device that needs the firmware is needed to access the
-+ filesystem. When upon some error the device has to be reset and the
-+ firmware reloaded, it won't be possible to get it from userspace.
-+ e.g.:
-+ - A diskless client with a network card that needs firmware.
-+ - The filesystem is stored in a disk behind an scsi device
-+ that needs firmware.
-+ - Replacing buggy DSDT/SSDT ACPI tables on boot.
-+ Note: this would require the persistent objects to be included
-+ within the kernel image, probably within initramfs.
-+
-+ And the same device can be needed to access the filesystem or not depending
-+ on the setup, so I think that the choice on what firmware to make
-+ persistent should be left to userspace.
-+
-+ - Why register_firmware()+__init can be useful:
-+ - For boot devices needing firmware.
-+ - To make the transition easier:
-+ The firmware can be declared __init and register_firmware()
-+ called on module_init. Then the firmware is warranted to be
-+ there even if "firmware hotplug userspace" is not there yet or
-+ it doesn't yet provide the needed firmware.
-+ Once the firmware is widely available in userspace, it can be
-+ removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
-+
-+ In either case, if firmware hotplug support is there, it can move the
-+ firmware out of kernel memory into the real filesystem for later
-+ usage.
-+
-+ Note: If persistence is implemented on top of initramfs,
-+ register_firmware() may not be appropriate.
-diff -urN linux-2.4.18/drivers/bluetooth/bfusb.c linux-2.4.18-mh15/drivers/bluetooth/bfusb.c
---- linux-2.4.18/drivers/bluetooth/bfusb.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/bfusb.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,782 @@
-+/*
-+ *
-+ * AVM BlueFRITZ! USB driver
-+ *
-+ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/skbuff.h>
-+
-+#include <linux/firmware.h>
-+#include <linux/usb.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.1"
-+
-+static struct usb_device_id bfusb_table[] = {
-+ /* AVM BlueFRITZ! USB */
-+ { USB_DEVICE(0x057c, 0x2200) },
-+
-+ { } /* Terminating entry */
-+};
-+
-+MODULE_DEVICE_TABLE(usb, bfusb_table);
-+
-+
-+#define BFUSB_MAX_BLOCK_SIZE 256
-+
-+#define BFUSB_BLOCK_TIMEOUT (HZ * 3)
-+
-+#define BFUSB_TX_PROCESS 1
-+#define BFUSB_TX_WAKEUP 2
-+
-+#define BFUSB_MAX_BULK_TX 1
-+#define BFUSB_MAX_BULK_RX 1
-+
-+struct bfusb {
-+ struct hci_dev hdev;
-+
-+ unsigned long state;
-+
-+ struct usb_device *udev;
-+
-+ unsigned int bulk_in_ep;
-+ unsigned int bulk_out_ep;
-+ unsigned int bulk_pkt_size;
-+
-+ rwlock_t lock;
-+
-+ struct sk_buff_head transmit_q;
-+
-+ struct sk_buff *reassembly;
-+
-+ atomic_t pending_tx;
-+ struct sk_buff_head pending_q;
-+ struct sk_buff_head completed_q;
-+};
-+
-+struct bfusb_scb {
-+ struct urb *urb;
-+};
-+
-+static void bfusb_tx_complete(struct urb *urb);
-+static void bfusb_rx_complete(struct urb *urb);
-+
-+static struct urb *bfusb_get_completed(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+ struct urb *urb = NULL;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ skb = skb_dequeue(&bfusb->completed_q);
-+ if (skb) {
-+ urb = ((struct bfusb_scb *) skb->cb)->urb;
-+ kfree_skb(skb);
-+ }
-+
-+ return urb;
-+}
-+
-+static inline void bfusb_unlink_urbs(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+ struct urb *urb;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ while ((skb = skb_dequeue(&bfusb->pending_q))) {
-+ urb = ((struct bfusb_scb *) skb->cb)->urb;
-+ usb_unlink_urb(urb);
-+ skb_queue_tail(&bfusb->completed_q, skb);
-+ }
-+
-+ while ((urb = bfusb_get_completed(bfusb)))
-+ usb_free_urb(urb);
-+}
-+
-+
-+static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
-+{
-+ struct bfusb_scb *scb = (void *) skb->cb;
-+ struct urb *urb = bfusb_get_completed(bfusb);
-+ int err, pipe;
-+
-+ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
-+
-+ if (!urb && !(urb = usb_alloc_urb(0)))
-+ return -ENOMEM;
-+
-+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len,
-+ bfusb_tx_complete, skb);
-+
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ scb->urb = urb;
-+
-+ skb_queue_tail(&bfusb->pending_q, skb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk tx submit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ skb_unlink(skb);
-+ usb_free_urb(urb);
-+ } else
-+ atomic_inc(&bfusb->pending_tx);
-+
-+ return err;
-+}
-+
-+static void bfusb_tx_wakeup(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
-+ set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+ return;
-+ }
-+
-+ do {
-+ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+
-+ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
-+ (skb = skb_dequeue(&bfusb->transmit_q))) {
-+ if (bfusb_send_bulk(bfusb, skb) < 0) {
-+ skb_queue_head(&bfusb->transmit_q, skb);
-+ break;
-+ }
-+ }
-+
-+ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
-+
-+ clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
-+}
-+
-+static void bfusb_tx_complete(struct urb *urb)
-+{
-+ struct sk_buff *skb = (struct sk_buff *) urb->context;
-+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+
-+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+ atomic_dec(&bfusb->pending_tx);
-+
-+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+ return;
-+
-+ if (!urb->status)
-+ bfusb->hdev.stat.byte_tx += skb->len;
-+ else
-+ bfusb->hdev.stat.err_tx++;
-+
-+ read_lock(&bfusb->lock);
-+
-+ skb_unlink(skb);
-+ skb_queue_tail(&bfusb->completed_q, skb);
-+
-+ bfusb_tx_wakeup(bfusb);
-+
-+ read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
-+{
-+ struct bfusb_scb *scb;
-+ struct sk_buff *skb;
-+ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
-+
-+ BT_DBG("bfusb %p urb %p", bfusb, urb);
-+
-+ if (!urb && !(urb = usb_alloc_urb(0)))
-+ return -ENOMEM;
-+
-+ if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
-+ usb_free_urb(urb);
-+ return -ENOMEM;
-+ }
-+
-+ skb->dev = (void *) bfusb;
-+
-+ scb = (struct bfusb_scb *) skb->cb;
-+ scb->urb = urb;
-+
-+ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
-+
-+ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size,
-+ bfusb_rx_complete, skb);
-+
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ skb_queue_tail(&bfusb->pending_q, skb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk rx submit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ skb_unlink(skb);
-+ kfree_skb(skb);
-+ usb_free_urb(urb);
-+ }
-+
-+ return err;
-+}
-+
-+static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
-+{
-+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
-+
-+ if (hdr & 0x10) {
-+ BT_ERR("%s error in block", bfusb->hdev.name);
-+ if (bfusb->reassembly)
-+ kfree_skb(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ return -EIO;
-+ }
-+
-+ if (hdr & 0x04) {
-+ struct sk_buff *skb;
-+ unsigned char pkt_type;
-+ int pkt_len = 0;
-+
-+ if (bfusb->reassembly) {
-+ BT_ERR("%s unexpected start block", bfusb->hdev.name);
-+ kfree_skb(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ }
-+
-+ if (len < 1) {
-+ BT_ERR("%s no packet type found", bfusb->hdev.name);
-+ return -EPROTO;
-+ }
-+
-+ pkt_type = *data++; len--;
-+
-+ switch (pkt_type) {
-+ case HCI_EVENT_PKT:
-+ if (len >= HCI_EVENT_HDR_SIZE) {
-+ hci_event_hdr *hdr = (hci_event_hdr *) data;
-+ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
-+ } else {
-+ BT_ERR("%s event block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ if (len >= HCI_ACL_HDR_SIZE) {
-+ hci_acl_hdr *hdr = (hci_acl_hdr *) data;
-+ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
-+ } else {
-+ BT_ERR("%s data block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ if (len >= HCI_SCO_HDR_SIZE) {
-+ hci_sco_hdr *hdr = (hci_sco_hdr *) data;
-+ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
-+ } else {
-+ BT_ERR("%s audio block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+ }
-+
-+ skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s no memory for the packet", bfusb->hdev.name);
-+ return -ENOMEM;
-+ }
-+
-+ skb->dev = (void *) &bfusb->hdev;
-+ skb->pkt_type = pkt_type;
-+
-+ bfusb->reassembly = skb;
-+ } else {
-+ if (!bfusb->reassembly) {
-+ BT_ERR("%s unexpected continuation block", bfusb->hdev.name);
-+ return -EIO;
-+ }
-+ }
-+
-+ if (len > 0)
-+ memcpy(skb_put(bfusb->reassembly, len), data, len);
-+
-+ if (hdr & 0x08) {
-+ hci_recv_frame(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ }
-+
-+ return 0;
-+}
-+
-+static void bfusb_rx_complete(struct urb *urb)
-+{
-+ struct sk_buff *skb = (struct sk_buff *) urb->context;
-+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+ unsigned char *buf = urb->transfer_buffer;
-+ int count = urb->actual_length;
-+ int err, hdr, len;
-+
-+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+ read_lock(&bfusb->lock);
-+
-+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+ goto unlock;
-+
-+ if (urb->status || !count)
-+ goto resubmit;
-+
-+ bfusb->hdev.stat.byte_rx += count;
-+
-+ skb_put(skb, count);
-+
-+ while (count) {
-+ hdr = buf[0] | (buf[1] << 8);
-+
-+ if (hdr & 0x4000) {
-+ len = 0;
-+ count -= 2;
-+ buf += 2;
-+ } else {
-+ len = (buf[2] == 0) ? 256 : buf[2];
-+ count -= 3;
-+ buf += 3;
-+ }
-+
-+ if (count < len) {
-+ BT_ERR("%s block extends over URB buffer ranges",
-+ bfusb->hdev.name);
-+ }
-+
-+ if ((hdr & 0xe1) == 0xc1)
-+ bfusb_recv_block(bfusb, hdr, buf, len);
-+
-+ count -= len;
-+ buf += len;
-+ }
-+
-+ skb_unlink(skb);
-+ kfree_skb(skb);
-+
-+ bfusb_rx_submit(bfusb, urb);
-+
-+ read_unlock(&bfusb->lock);
-+
-+ return;
-+
-+resubmit:
-+ urb->dev = bfusb->udev;
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk resubmit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ }
-+
-+unlock:
-+ read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_open(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+ unsigned long flags;
-+ int i, err;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ write_lock_irqsave(&bfusb->lock, flags);
-+
-+ err = bfusb_rx_submit(bfusb, NULL);
-+ if (!err) {
-+ for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
-+ bfusb_rx_submit(bfusb, NULL);
-+ } else {
-+ clear_bit(HCI_RUNNING, &hdev->flags);
-+ MOD_DEC_USE_COUNT;
-+ }
-+
-+ write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+ return err;
-+}
-+
-+static int bfusb_flush(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ skb_queue_purge(&bfusb->transmit_q);
-+
-+ return 0;
-+}
-+
-+static int bfusb_close(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+ unsigned long flags;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ write_lock_irqsave(&bfusb->lock, flags);
-+
-+ bfusb_unlink_urbs(bfusb);
-+ bfusb_flush(hdev);
-+
-+ write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int bfusb_send_frame(struct sk_buff *skb)
-+{
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-+ struct bfusb *bfusb;
-+ struct sk_buff *nskb;
-+ unsigned char buf[3];
-+ int sent = 0, size, count;
-+
-+ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
-+
-+ if (!hdev) {
-+ BT_ERR("Frame for unknown HCI device (hdev=NULL)");
-+ return -ENODEV;
-+ }
-+
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-+
-+ bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+
-+ count = skb->len;
-+
-+ /* Max HCI frame size seems to be 1511 + 1 */
-+ if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new packet");
-+ return -ENOMEM;
-+ }
-+
-+ nskb->dev = (void *) bfusb;
-+
-+ while (count) {
-+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
-+
-+ buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
-+ buf[1] = 0x00;
-+ buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
-+
-+ memcpy(skb_put(nskb, 3), buf, 3);
-+ memcpy(skb_put(nskb, size), skb->data + sent, size);
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ /* Don't send frame with multiple size of bulk max packet */
-+ if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
-+ buf[0] = 0xdd;
-+ buf[1] = 0x00;
-+ memcpy(skb_put(nskb, 2), buf, 2);
-+ }
-+
-+ read_lock(&bfusb->lock);
-+
-+ skb_queue_tail(&bfusb->transmit_q, nskb);
-+ bfusb_tx_wakeup(bfusb);
-+
-+ read_unlock(&bfusb->lock);
-+
-+ kfree_skb(skb);
-+
-+ return 0;
-+}
-+
-+static void bfusb_destruct(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ kfree(bfusb);
-+}
-+
-+static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
-+{
-+ unsigned char *buf;
-+ int err, pipe, len, size, sent = 0;
-+
-+ BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count);
-+
-+ BT_INFO("BlueFRITZ! USB loading firmware");
-+
-+ if (usb_set_configuration(bfusb->udev, 1) < 0) {
-+ BT_ERR("Can't change to loading configuration");
-+ return -EBUSY;
-+ }
-+
-+ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
-+ if (!buf) {
-+ BT_ERR("Can't allocate memory chunk for firmware");
-+ return -ENOMEM;
-+ }
-+
-+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+ while (count) {
-+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
-+
-+ memcpy(buf, firmware + sent, size);
-+
-+ err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
-+ &len, BFUSB_BLOCK_TIMEOUT);
-+
-+ if (err || (len != size)) {
-+ BT_ERR("Error in firmware loading");
-+ goto error;
-+ }
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
-+ &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
-+ BT_ERR("Error in null packet request");
-+ goto error;
-+ }
-+
-+ if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) {
-+ BT_ERR("Can't change to running configuration");
-+ goto error;
-+ }
-+
-+ BT_INFO("BlueFRITZ! USB device ready");
-+
-+ kfree(buf);
-+ return 0;
-+
-+error:
-+ kfree(buf);
-+
-+ pipe = usb_sndctrlpipe(bfusb->udev, 0);
-+
-+ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-+ 0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT);
-+
-+ return err;
-+}
-+
-+static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+{
-+ const struct firmware *firmware;
-+ char device[16];
-+ struct usb_interface *iface;
-+ struct usb_interface_descriptor *iface_desc;
-+ struct usb_endpoint_descriptor *bulk_out_ep;
-+ struct usb_endpoint_descriptor *bulk_in_ep;
-+ struct hci_dev *hdev;
-+ struct bfusb *bfusb;
-+
-+ BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id);
-+
-+ /* Check number of endpoints */
-+ iface = &udev->actconfig->interface[0];
-+ iface_desc = &iface->altsetting[0];
-+
-+ if (iface_desc->bNumEndpoints < 2)
-+ return NULL;
-+
-+ bulk_out_ep = &iface_desc->endpoint[0];
-+ bulk_in_ep = &iface_desc->endpoint[1];
-+
-+ if (!bulk_out_ep || !bulk_in_ep) {
-+ BT_ERR("Bulk endpoints not found");
-+ goto done;
-+ }
-+
-+ /* Initialize control structure and load firmware */
-+ if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) {
-+ BT_ERR("Can't allocate memory for control structure");
-+ goto done;
-+ }
-+
-+ memset(bfusb, 0, sizeof(struct bfusb));
-+
-+ bfusb->udev = udev;
-+ bfusb->bulk_in_ep = bulk_in_ep->bEndpointAddress;
-+ bfusb->bulk_out_ep = bulk_out_ep->bEndpointAddress;
-+ bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize;
-+
-+ bfusb->lock = RW_LOCK_UNLOCKED;
-+
-+ bfusb->reassembly = NULL;
-+
-+ skb_queue_head_init(&bfusb->transmit_q);
-+ skb_queue_head_init(&bfusb->pending_q);
-+ skb_queue_head_init(&bfusb->completed_q);
-+
-+ snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum);
-+
-+ if (request_firmware(&firmware, "bfubase.frm", device) < 0) {
-+ BT_ERR("Firmware request failed");
-+ goto error;
-+ }
-+
-+ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
-+ BT_ERR("Firmware loading failed");
-+ goto release;
-+ }
-+
-+ release_firmware(firmware);
-+
-+ /* Initialize and register HCI device */
-+ hdev = &bfusb->hdev;
-+
-+ hdev->type = HCI_USB;
-+ hdev->driver_data = bfusb;
-+
-+ hdev->open = bfusb_open;
-+ hdev->close = bfusb_close;
-+ hdev->flush = bfusb_flush;
-+ hdev->send = bfusb_send_frame;
-+ hdev->destruct = bfusb_destruct;
-+ hdev->ioctl = bfusb_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ BT_ERR("Can't register HCI device");
-+ goto error;
-+ }
-+
-+ return bfusb;
-+
-+release:
-+ release_firmware(firmware);
-+
-+error:
-+ kfree(bfusb);
-+
-+done:
-+ return NULL;
-+}
-+
-+static void bfusb_disconnect(struct usb_device *udev, void *ptr)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) ptr;
-+ struct hci_dev *hdev = &bfusb->hdev;
-+
-+ BT_DBG("udev %p ptr %p", udev, ptr);
-+
-+ if (!hdev)
-+ return;
-+
-+ bfusb_close(hdev);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ BT_ERR("Can't unregister HCI device %s", hdev->name);
-+}
-+
-+static struct usb_driver bfusb_driver = {
-+ name: "bfusb",
-+ probe: bfusb_probe,
-+ disconnect: bfusb_disconnect,
-+ id_table: bfusb_table,
-+};
-+
-+static int __init bfusb_init(void)
-+{
-+ int err;
-+
-+ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ if ((err = usb_register(&bfusb_driver)) < 0)
-+ BT_ERR("Failed to register BlueFRITZ! USB driver");
-+
-+ return err;
-+}
-+
-+static void __exit bfusb_cleanup(void)
-+{
-+ usb_deregister(&bfusb_driver);
-+}
-+
-+module_init(bfusb_init);
-+module_exit(bfusb_cleanup);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/bluecard_cs.c linux-2.4.18-mh15/drivers/bluetooth/bluecard_cs.c
---- linux-2.4.18/drivers/bluetooth/bluecard_cs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/bluecard_cs.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,1116 @@
-+/*
-+ *
-+ * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+#include <linux/skbuff.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0x86bc;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct bluecard_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+ struct timer_list timer; /* For LED control */
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+
-+ unsigned char ctrl_reg;
-+ unsigned long hw_state; /* Status of the hardware and LED control */
-+} bluecard_info_t;
-+
-+
-+void bluecard_config(dev_link_t *link);
-+void bluecard_release(u_long arg);
-+int bluecard_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "bluecard_cs";
-+
-+dev_link_t *bluecard_attach(void);
-+void bluecard_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Default baud rate: 57600, 115200, 230400 or 460800 */
-+#define DEFAULT_BAUD_RATE 230400
-+
-+
-+/* Hardware states */
-+#define CARD_READY 1
-+#define CARD_HAS_PCCARD_ID 4
-+#define CARD_HAS_POWER_LED 5
-+#define CARD_HAS_ACTIVITY_LED 6
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */
-+#define XMIT_BUF_ONE_READY 6
-+#define XMIT_BUF_TWO_READY 7
-+#define XMIT_SENDING_READY 8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER 1
-+#define RECV_WAIT_ACL_HEADER 2
-+#define RECV_WAIT_SCO_HEADER 3
-+#define RECV_WAIT_DATA 4
-+
-+/* Special packet types */
-+#define PKT_BAUD_RATE_57600 0x80
-+#define PKT_BAUD_RATE_115200 0x81
-+#define PKT_BAUD_RATE_230400 0x82
-+#define PKT_BAUD_RATE_460800 0x83
-+
-+
-+/* These are the register offsets */
-+#define REG_COMMAND 0x20
-+#define REG_INTERRUPT 0x21
-+#define REG_CONTROL 0x22
-+#define REG_RX_CONTROL 0x24
-+#define REG_CARD_RESET 0x30
-+#define REG_LED_CTRL 0x30
-+
-+/* REG_COMMAND */
-+#define REG_COMMAND_TX_BUF_ONE 0x01
-+#define REG_COMMAND_TX_BUF_TWO 0x02
-+#define REG_COMMAND_RX_BUF_ONE 0x04
-+#define REG_COMMAND_RX_BUF_TWO 0x08
-+#define REG_COMMAND_RX_WIN_ONE 0x00
-+#define REG_COMMAND_RX_WIN_TWO 0x10
-+
-+/* REG_CONTROL */
-+#define REG_CONTROL_BAUD_RATE_57600 0x00
-+#define REG_CONTROL_BAUD_RATE_115200 0x01
-+#define REG_CONTROL_BAUD_RATE_230400 0x02
-+#define REG_CONTROL_BAUD_RATE_460800 0x03
-+#define REG_CONTROL_RTS 0x04
-+#define REG_CONTROL_BT_ON 0x08
-+#define REG_CONTROL_BT_RESET 0x10
-+#define REG_CONTROL_BT_RES_PU 0x20
-+#define REG_CONTROL_INTERRUPT 0x40
-+#define REG_CONTROL_CARD_RESET 0x80
-+
-+/* REG_RX_CONTROL */
-+#define RTS_LEVEL_SHIFT_BITS 0x02
-+
-+
-+
-+/* ======================== LED handling routines ======================== */
-+
-+
-+void bluecard_activity_led_timeout(u_long arg)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)arg;
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
-+ /* Disable activity LED */
-+ outb(0x08 | 0x20, iobase + 0x30);
-+ } else {
-+ /* Disable power LED */
-+ outb(0x00, iobase + 0x30);
-+ }
-+}
-+
-+
-+static void bluecard_enable_activity_led(bluecard_info_t *info)
-+{
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
-+ /* Enable activity LED */
-+ outb(0x10 | 0x40, iobase + 0x30);
-+
-+ /* Stop the LED after HZ/4 */
-+ mod_timer(&(info->timer), jiffies + HZ / 4);
-+ } else {
-+ /* Enable power LED */
-+ outb(0x08 | 0x20, iobase + 0x30);
-+
-+ /* Stop the LED after HZ/2 */
-+ mod_timer(&(info->timer), jiffies + HZ / 2);
-+ }
-+}
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
-+{
-+ int i, actual;
-+
-+ actual = (len > 15) ? 15 : len;
-+
-+ outb_p(actual, iobase + offset);
-+
-+ for (i = 0; i < actual; i++)
-+ outb_p(buf[i], iobase + offset + i + 1);
-+
-+ return actual;
-+}
-+
-+
-+static void bluecard_write_wakeup(bluecard_info_t *info)
-+{
-+ if (!info) {
-+ printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
-+ return;
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register unsigned int offset;
-+ register unsigned char command;
-+ register unsigned long ready_bit;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ return;
-+
-+ if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
-+ if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
-+ break;
-+ offset = 0x10;
-+ command = REG_COMMAND_TX_BUF_TWO;
-+ ready_bit = XMIT_BUF_TWO_READY;
-+ } else {
-+ if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
-+ break;
-+ offset = 0x00;
-+ command = REG_COMMAND_TX_BUF_ONE;
-+ ready_bit = XMIT_BUF_ONE_READY;
-+ }
-+
-+ if (!(skb = skb_dequeue(&(info->txq))))
-+ break;
-+
-+ if (skb->pkt_type & 0x80) {
-+ /* Disable RTS */
-+ info->ctrl_reg |= REG_CONTROL_RTS;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+ }
-+
-+ /* Activate LED */
-+ bluecard_enable_activity_led(info);
-+
-+ /* Send frame */
-+ len = bluecard_write(iobase, offset, skb->data, skb->len);
-+
-+ /* Tell the FPGA to send the data */
-+ outb_p(command, iobase + REG_COMMAND);
-+
-+ /* Mark the buffer as dirty */
-+ clear_bit(ready_bit, &(info->tx_state));
-+
-+ if (skb->pkt_type & 0x80) {
-+
-+ wait_queue_head_t wait;
-+ unsigned char baud_reg;
-+
-+ switch (skb->pkt_type) {
-+ case PKT_BAUD_RATE_460800:
-+ baud_reg = REG_CONTROL_BAUD_RATE_460800;
-+ break;
-+ case PKT_BAUD_RATE_230400:
-+ baud_reg = REG_CONTROL_BAUD_RATE_230400;
-+ break;
-+ case PKT_BAUD_RATE_115200:
-+ baud_reg = REG_CONTROL_BAUD_RATE_115200;
-+ break;
-+ case PKT_BAUD_RATE_57600:
-+ /* Fall through... */
-+ default:
-+ baud_reg = REG_CONTROL_BAUD_RATE_57600;
-+ break;
-+ }
-+
-+ /* Wait until the command reaches the baseband */
-+ init_waitqueue_head(&wait);
-+ interruptible_sleep_on_timeout(&wait, HZ / 10);
-+
-+ /* Set baud on baseband */
-+ info->ctrl_reg &= ~0x03;
-+ info->ctrl_reg |= baud_reg;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Enable RTS */
-+ info->ctrl_reg &= ~REG_CONTROL_RTS;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Wait before the next HCI packet can be send */
-+ interruptible_sleep_on_timeout(&wait, HZ);
-+
-+ }
-+
-+ if (len == skb->len) {
-+ kfree_skb(skb);
-+ } else {
-+ skb_pull(skb, len);
-+ skb_queue_head(&(info->txq), skb);
-+ }
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ /* Change buffer */
-+ change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
-+
-+ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
-+{
-+ int i, n, len;
-+
-+ outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
-+
-+ len = inb(iobase + offset);
-+ n = 0;
-+ i = 1;
-+
-+ while (n < len) {
-+
-+ if (i == 16) {
-+ outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
-+ i = 0;
-+ }
-+
-+ buf[n] = inb(iobase + offset + i);
-+
-+ n++;
-+ i++;
-+
-+ }
-+
-+ return len;
-+}
-+
-+
-+static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
-+{
-+ unsigned int iobase;
-+ unsigned char buf[31];
-+ int i, len;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
-+ bluecard_enable_activity_led(info);
-+
-+ len = bluecard_read(iobase, offset, buf, sizeof(buf));
-+
-+ for (i = 0; i < len; i++) {
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL) {
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
-+ return;
-+ }
-+ }
-+
-+ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type = buf[i];
-+
-+ switch (info->rx_skb->pkt_type) {
-+
-+ case 0x00:
-+ /* init packet */
-+ if (offset != 0x00) {
-+ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
-+ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
-+ set_bit(XMIT_SENDING_READY, &(info->tx_state));
-+ bluecard_write_wakeup(info);
-+ }
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ case HCI_EVENT_PKT:
-+ info->rx_state = RECV_WAIT_EVENT_HEADER;
-+ info->rx_count = HCI_EVENT_HDR_SIZE;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ info->rx_state = RECV_WAIT_ACL_HEADER;
-+ info->rx_count = HCI_ACL_HDR_SIZE;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ info->rx_state = RECV_WAIT_SCO_HEADER;
-+ info->rx_count = HCI_SCO_HDR_SIZE;
-+ break;
-+
-+ default:
-+ /* unknown packet */
-+ printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ info->hdev.stat.err_rx++;
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ } else {
-+
-+ *skb_put(info->rx_skb, 1) = buf[i];
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ int dlen;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+
-+ switch (info->rx_state) {
-+
-+ case RECV_WAIT_EVENT_HEADER:
-+ eh = (hci_event_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = eh->plen;
-+ break;
-+
-+ case RECV_WAIT_ACL_HEADER:
-+ ah = (hci_acl_hdr *)(info->rx_skb->data);
-+ dlen = __le16_to_cpu(ah->dlen);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = dlen;
-+ break;
-+
-+ case RECV_WAIT_SCO_HEADER:
-+ sh = (hci_sco_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = sh->dlen;
-+ break;
-+
-+ case RECV_WAIT_DATA:
-+ hci_recv_frame(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+
-+ }
-+
-+ info->hdev.stat.byte_rx += len;
-+}
-+
-+
-+void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ bluecard_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ unsigned char reg;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ if (!test_bit(CARD_READY, &(info->hw_state)))
-+ return;
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ /* Disable interrupt */
-+ info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ reg = inb(iobase + REG_INTERRUPT);
-+
-+ if ((reg != 0x00) && (reg != 0xff)) {
-+
-+ if (reg & 0x04) {
-+ bluecard_receive(info, 0x00);
-+ outb(0x04, iobase + REG_INTERRUPT);
-+ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
-+ }
-+
-+ if (reg & 0x08) {
-+ bluecard_receive(info, 0x10);
-+ outb(0x08, iobase + REG_INTERRUPT);
-+ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
-+ }
-+
-+ if (reg & 0x01) {
-+ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
-+ outb(0x01, iobase + REG_INTERRUPT);
-+ bluecard_write_wakeup(info);
-+ }
-+
-+ if (reg & 0x02) {
-+ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
-+ outb(0x02, iobase + REG_INTERRUPT);
-+ bluecard_write_wakeup(info);
-+ }
-+
-+ }
-+
-+ /* Enable interrupt */
-+ info->ctrl_reg |= REG_CONTROL_INTERRUPT;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+/* ======================== Device specific HCI commands ======================== */
-+
-+
-+static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+ struct sk_buff *skb;
-+
-+ /* Ericsson baud rate command */
-+ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
-+
-+ if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
-+ return -1;
-+ }
-+
-+ switch (baud) {
-+ case 460800:
-+ cmd[4] = 0x00;
-+ skb->pkt_type = PKT_BAUD_RATE_460800;
-+ break;
-+ case 230400:
-+ cmd[4] = 0x01;
-+ skb->pkt_type = PKT_BAUD_RATE_230400;
-+ break;
-+ case 115200:
-+ cmd[4] = 0x02;
-+ skb->pkt_type = PKT_BAUD_RATE_115200;
-+ break;
-+ case 57600:
-+ /* Fall through... */
-+ default:
-+ cmd[4] = 0x03;
-+ skb->pkt_type = PKT_BAUD_RATE_57600;
-+ break;
-+ }
-+
-+ memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
-+
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ bluecard_write_wakeup(info);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int bluecard_hci_flush(struct hci_dev *hdev)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int bluecard_hci_open(struct hci_dev *hdev)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
-+
-+ if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ /* Enable LED */
-+ outb(0x08 | 0x20, iobase + 0x30);
-+
-+ return 0;
-+}
-+
-+
-+static int bluecard_hci_close(struct hci_dev *hdev)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ bluecard_hci_flush(hdev);
-+
-+ /* Disable LED */
-+ outb(0x00, iobase + 0x30);
-+
-+ return 0;
-+}
-+
-+
-+static int bluecard_hci_send_frame(struct sk_buff *skb)
-+{
-+ bluecard_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (bluecard_info_t *)(hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ bluecard_write_wakeup(info);
-+
-+ return 0;
-+}
-+
-+
-+static void bluecard_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int bluecard_open(bluecard_info_t *info)
-+{
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev;
-+ unsigned char id;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ init_timer(&(info->timer));
-+ info->timer.function = &bluecard_activity_led_timeout;
-+ info->timer.data = (u_long)info;
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ info->rx_skb = NULL;
-+
-+ id = inb(iobase + 0x30);
-+
-+ if ((id & 0x0f) == 0x02)
-+ set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
-+
-+ if (id & 0x10)
-+ set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
-+
-+ if (id & 0x20)
-+ set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
-+
-+ /* Reset card */
-+ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Turn FPGA off */
-+ outb(0x80, iobase + 0x30);
-+
-+ /* Wait some time */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ / 100);
-+
-+ /* Turn FPGA on */
-+ outb(0x00, iobase + 0x30);
-+
-+ /* Activate card */
-+ info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Enable interrupt */
-+ outb(0xff, iobase + REG_INTERRUPT);
-+ info->ctrl_reg |= REG_CONTROL_INTERRUPT;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Start the RX buffers */
-+ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
-+ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
-+
-+ /* Signal that the hardware is ready */
-+ set_bit(CARD_READY, &(info->hw_state));
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ /* Control the point at which RTS is enabled */
-+ outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout((HZ * 5) / 4); // or set it to 3/2
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = bluecard_hci_open;
-+ hdev->close = bluecard_hci_close;
-+ hdev->flush = bluecard_hci_flush;
-+ hdev->send = bluecard_hci_send_frame;
-+ hdev->destruct = bluecard_hci_destruct;
-+ hdev->ioctl = bluecard_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int bluecard_close(bluecard_info_t *info)
-+{
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
-+ bluecard_hci_close(hdev);
-+
-+ clear_bit(CARD_READY, &(info->hw_state));
-+
-+ /* Reset card */
-+ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Turn FPGA off */
-+ outb(0x80, iobase + 0x30);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *bluecard_attach(void)
-+{
-+ bluecard_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &bluecard_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = bluecard_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &bluecard_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ bluecard_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void bluecard_detach(dev_link_t *link)
-+{
-+ bluecard_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+ if (link->state & DEV_CONFIG)
-+ bluecard_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void bluecard_config(dev_link_t *link)
-+{
-+ client_handle_t handle = link->handle;
-+ bluecard_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ config_info_t config;
-+ int i, n, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ link->conf.ConfigIndex = 0x20;
-+ link->io.NumPorts1 = 64;
-+ link->io.IOAddrLines = 6;
-+
-+ for (n = 0; n < 0x400; n += 0x40) {
-+ link->io.BasePort1 = n ^ 0x300;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ break;
-+ }
-+
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (bluecard_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ bluecard_release((u_long)link);
-+}
-+
-+
-+void bluecard_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ bluecard_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ bluecard_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int bluecard_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ bluecard_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ bluecard_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ bluecard_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_bluecard_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_bluecard_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ bluecard_detach(dev_list);
-+}
-+
-+
-+module_init(init_bluecard_cs);
-+module_exit(exit_bluecard_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/bt3c_cs.c linux-2.4.18-mh15/drivers/bluetooth/bt3c_cs.c
---- linux-2.4.18/drivers/bluetooth/bt3c_cs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/bt3c_cs.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,986 @@
-+/*
-+ *
-+ * Driver for the 3Com Bluetooth PCMCIA card
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ * Jose Orlando Pereira <jop@di.uminho.pt>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/kmod.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/unistd.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <linux/firmware.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
-+MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct bt3c_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+} bt3c_info_t;
-+
-+
-+void bt3c_config(dev_link_t *link);
-+void bt3c_release(u_long arg);
-+int bt3c_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "bt3c_cs";
-+
-+dev_link_t *bt3c_attach(void);
-+void bt3c_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_WAITING 8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER 1
-+#define RECV_WAIT_ACL_HEADER 2
-+#define RECV_WAIT_SCO_HEADER 3
-+#define RECV_WAIT_DATA 4
-+
-+
-+
-+/* ======================== Special I/O functions ======================== */
-+
-+
-+#define DATA_L 0
-+#define DATA_H 1
-+#define ADDR_L 2
-+#define ADDR_H 3
-+#define CONTROL 4
-+
-+
-+inline void bt3c_address(unsigned int iobase, unsigned short addr)
-+{
-+ outb(addr & 0xff, iobase + ADDR_L);
-+ outb((addr >> 8) & 0xff, iobase + ADDR_H);
-+}
-+
-+
-+inline void bt3c_put(unsigned int iobase, unsigned short value)
-+{
-+ outb(value & 0xff, iobase + DATA_L);
-+ outb((value >> 8) & 0xff, iobase + DATA_H);
-+}
-+
-+
-+inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
-+{
-+ bt3c_address(iobase, addr);
-+ bt3c_put(iobase, value);
-+}
-+
-+
-+inline unsigned short bt3c_get(unsigned int iobase)
-+{
-+ unsigned short value = inb(iobase + DATA_L);
-+
-+ value |= inb(iobase + DATA_H) << 8;
-+
-+ return value;
-+}
-+
-+
-+inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
-+{
-+ bt3c_address(iobase, addr);
-+
-+ return bt3c_get(iobase);
-+}
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+ int actual = 0;
-+
-+ bt3c_address(iobase, 0x7080);
-+
-+ /* Fill FIFO with current frame */
-+ while (actual < len) {
-+ /* Transmit next byte */
-+ bt3c_put(iobase, buf[actual]);
-+ actual++;
-+ }
-+
-+ bt3c_io_write(iobase, 0x7005, actual);
-+
-+ return actual;
-+}
-+
-+
-+static void bt3c_write_wakeup(bt3c_info_t *info, int from)
-+{
-+ unsigned long flags;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
-+ return;
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ break;
-+
-+
-+ if (!(skb = skb_dequeue(&(info->txq)))) {
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+ break;
-+ }
-+
-+ /* Send frame */
-+ len = bt3c_write(iobase, 256, skb->data, skb->len);
-+
-+ if (len != skb->len) {
-+ printk(KERN_WARNING "bt3c_cs: very strange\n");
-+ }
-+
-+ kfree_skb(skb);
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ } while (0);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+}
-+
-+
-+static void bt3c_receive(bt3c_info_t *info)
-+{
-+ unsigned int iobase;
-+ int size = 0, avail;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ avail = bt3c_read(iobase, 0x7006);
-+ //printk("bt3c_cs: receiving %d bytes\n", avail);
-+
-+ bt3c_address(iobase, 0x7480);
-+ while (size < avail) {
-+ size++;
-+ info->hdev.stat.byte_rx++;
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL) {
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
-+ return;
-+ }
-+ }
-+
-+
-+ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type = inb(iobase + DATA_L);
-+ inb(iobase + DATA_H);
-+ //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
-+
-+ switch (info->rx_skb->pkt_type) {
-+
-+ case HCI_EVENT_PKT:
-+ info->rx_state = RECV_WAIT_EVENT_HEADER;
-+ info->rx_count = HCI_EVENT_HDR_SIZE;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ info->rx_state = RECV_WAIT_ACL_HEADER;
-+ info->rx_count = HCI_ACL_HDR_SIZE;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ info->rx_state = RECV_WAIT_SCO_HEADER;
-+ info->rx_count = HCI_SCO_HDR_SIZE;
-+ break;
-+
-+ default:
-+ /* Unknown packet */
-+ printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ info->hdev.stat.err_rx++;
-+ clear_bit(HCI_RUNNING, &(info->hdev.flags));
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ } else {
-+
-+ __u8 x = inb(iobase + DATA_L);
-+
-+ *skb_put(info->rx_skb, 1) = x;
-+ inb(iobase + DATA_H);
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ int dlen;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+
-+ switch (info->rx_state) {
-+
-+ case RECV_WAIT_EVENT_HEADER:
-+ eh = (hci_event_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = eh->plen;
-+ break;
-+
-+ case RECV_WAIT_ACL_HEADER:
-+ ah = (hci_acl_hdr *)(info->rx_skb->data);
-+ dlen = __le16_to_cpu(ah->dlen);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = dlen;
-+ break;
-+
-+ case RECV_WAIT_SCO_HEADER:
-+ sh = (hci_sco_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = sh->dlen;
-+ break;
-+
-+ case RECV_WAIT_DATA:
-+ hci_recv_frame(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+ bt3c_io_write(iobase, 0x7006, 0x0000);
-+}
-+
-+
-+void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ bt3c_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ int iir;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ iir = inb(iobase + CONTROL);
-+ if (iir & 0x80) {
-+ int stat = bt3c_read(iobase, 0x7001);
-+
-+ if ((stat & 0xff) == 0x7f) {
-+ printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
-+ } else if ((stat & 0xff) != 0xff) {
-+ if (stat & 0x0020) {
-+ int stat = bt3c_read(iobase, 0x7002) & 0x10;
-+ printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
-+ }
-+ if (stat & 0x0001)
-+ bt3c_receive(info);
-+ if (stat & 0x0002) {
-+ //printk("bt3c_cs: ACK %04x\n", stat);
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+ bt3c_write_wakeup(info, 1);
-+ }
-+
-+ bt3c_io_write(iobase, 0x7001, 0x0000);
-+
-+ outb(iir, iobase + CONTROL);
-+ }
-+ }
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int bt3c_hci_flush(struct hci_dev *hdev)
-+{
-+ bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int bt3c_hci_open(struct hci_dev *hdev)
-+{
-+ set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+ return 0;
-+}
-+
-+
-+static int bt3c_hci_close(struct hci_dev *hdev)
-+{
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ bt3c_hci_flush(hdev);
-+
-+ return 0;
-+}
-+
-+
-+static int bt3c_hci_send_frame(struct sk_buff *skb)
-+{
-+ bt3c_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (bt3c_info_t *) (hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ bt3c_write_wakeup(info, 0);
-+
-+ return 0;
-+}
-+
-+
-+static void bt3c_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count)
-+{
-+ char *ptr = (char *) firmware;
-+ char b[9];
-+ unsigned int iobase, size, addr, fcs, tmp;
-+ int i, err = 0;
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ /* Reset */
-+
-+ bt3c_io_write(iobase, 0x8040, 0x0404);
-+ bt3c_io_write(iobase, 0x8040, 0x0400);
-+
-+ udelay(1);
-+
-+ bt3c_io_write(iobase, 0x8040, 0x0404);
-+
-+ udelay(17);
-+
-+ /* Load */
-+
-+ while (count) {
-+ if (ptr[0] != 'S') {
-+ printk(KERN_WARNING "bt3c_cs: Bad address in firmware.\n");
-+ err = -EFAULT;
-+ goto error;
-+ }
-+
-+ memset(b, 0, sizeof(b));
-+ memcpy(b, ptr + 2, 2);
-+ size = simple_strtol(b, NULL, 16);
-+
-+ memset(b, 0, sizeof(b));
-+ memcpy(b, ptr + 4, 8);
-+ addr = simple_strtol(b, NULL, 16);
-+
-+ memset(b, 0, sizeof(b));
-+ memcpy(b, ptr + (size * 2) + 2, 2);
-+ fcs = simple_strtol(b, NULL, 16);
-+
-+ memset(b, 0, sizeof(b));
-+ for (tmp = 0, i = 0; i < size; i++) {
-+ memcpy(b, ptr + (i * 2) + 2, 2);
-+ tmp += simple_strtol(b, NULL, 16);
-+ }
-+
-+ if (((tmp + fcs) & 0xff) != 0xff) {
-+ printk(KERN_WARNING "bt3c_cs: Checksum error in firmware.\n");
-+ err = -EILSEQ;
-+ goto error;
-+ }
-+
-+ if (ptr[1] == '3') {
-+ bt3c_address(iobase, addr);
-+
-+ memset(b, 0, sizeof(b));
-+ for (i = 0; i < (size - 4) / 2; i++) {
-+ memcpy(b, ptr + (i * 4) + 12, 4);
-+ tmp = simple_strtol(b, NULL, 16);
-+ bt3c_put(iobase, tmp);
-+ }
-+ }
-+
-+ ptr += (size * 2) + 6;
-+ count -= (size * 2) + 6;
-+ }
-+
-+ udelay(17);
-+
-+ /* Boot */
-+
-+ bt3c_address(iobase, 0x3000);
-+ outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
-+
-+error:
-+ udelay(17);
-+
-+ /* Clear */
-+
-+ bt3c_io_write(iobase, 0x7006, 0x0000);
-+ bt3c_io_write(iobase, 0x7005, 0x0000);
-+ bt3c_io_write(iobase, 0x7001, 0x0000);
-+
-+ return err;
-+}
-+
-+
-+int bt3c_open(bt3c_info_t *info)
-+{
-+ const struct firmware *firmware;
-+ char device[16];
-+ struct hci_dev *hdev;
-+ int err;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ info->rx_skb = NULL;
-+
-+ /* Load firmware */
-+
-+ snprintf(device, sizeof(device), "bt3c%4.4x", info->link.io.BasePort1);
-+
-+ err = request_firmware(&firmware, "BT3CPCC.bin", device);
-+ if (err < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Firmware request failed.\n");
-+ return err;
-+ }
-+
-+ err = bt3c_load_firmware(info, firmware->data, firmware->size);
-+
-+ release_firmware(firmware);
-+
-+ if (err < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Firmware loading failed.\n");
-+ return err;
-+ }
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ);
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = bt3c_hci_open;
-+ hdev->close = bt3c_hci_close;
-+ hdev->flush = bt3c_hci_flush;
-+ hdev->send = bt3c_hci_send_frame;
-+ hdev->destruct = bt3c_hci_destruct;
-+ hdev->ioctl = bt3c_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int bt3c_close(bt3c_info_t *info)
-+{
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
-+ bt3c_hci_close(hdev);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *bt3c_attach(void)
-+{
-+ bt3c_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &bt3c_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = bt3c_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &bt3c_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ bt3c_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void bt3c_detach(dev_link_t *link)
-+{
-+ bt3c_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+
-+ if (link->state & DEV_CONFIG)
-+ bt3c_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void bt3c_config(dev_link_t *link)
-+{
-+ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-+ client_handle_t handle = link->handle;
-+ bt3c_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
-+ int i, j, try, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ /* First pass: look for a config entry that looks normal. */
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+ /* Two tries: without IO aliases, then with aliases */
-+ for (try = 0; try < 2; try++) {
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if (i != CS_SUCCESS)
-+ goto next_entry;
-+ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-+ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-+ link->conf.ConfigIndex = cf->index;
-+ link->io.BasePort1 = cf->io.win[0].base;
-+ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+next_entry:
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+ }
-+
-+ /* Second pass: try to find an entry that isn't picky about
-+ its base address, then try to grab any standard serial port
-+ address, and finally try to get any free port. */
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-+ link->conf.ConfigIndex = cf->index;
-+ for (j = 0; j < 5; j++) {
-+ link->io.BasePort1 = base[j];
-+ link->io.IOAddrLines = base[j] ? 16 : 3;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+ }
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+
-+found_port:
-+ if (i != CS_SUCCESS) {
-+ printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n");
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (bt3c_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ bt3c_release((u_long)link);
-+}
-+
-+
-+void bt3c_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ bt3c_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ bt3c_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int bt3c_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ bt3c_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ bt3c_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ bt3c_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_bt3c_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_bt3c_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ bt3c_detach(dev_list);
-+}
-+
-+
-+module_init(init_bt3c_cs);
-+module_exit(exit_bt3c_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/btuart_cs.c linux-2.4.18-mh15/drivers/bluetooth/btuart_cs.c
---- linux-2.4.18/drivers/bluetooth/btuart_cs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/btuart_cs.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,909 @@
-+/*
-+ *
-+ * Driver for Bluetooth PCMCIA cards with HCI UART interface
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct btuart_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+} btuart_info_t;
-+
-+
-+void btuart_config(dev_link_t *link);
-+void btuart_release(u_long arg);
-+int btuart_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "btuart_cs";
-+
-+dev_link_t *btuart_attach(void);
-+void btuart_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Maximum baud rate */
-+#define SPEED_MAX 115200
-+
-+/* Default baud rate: 57600, 115200, 230400 or 460800 */
-+#define DEFAULT_BAUD_RATE 115200
-+
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_WAITING 8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER 1
-+#define RECV_WAIT_ACL_HEADER 2
-+#define RECV_WAIT_SCO_HEADER 3
-+#define RECV_WAIT_DATA 4
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+ int actual = 0;
-+
-+ /* Tx FIFO should be empty */
-+ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-+ return 0;
-+
-+ /* Fill FIFO with current frame */
-+ while ((fifo_size-- > 0) && (actual < len)) {
-+ /* Transmit next byte */
-+ outb(buf[actual], iobase + UART_TX);
-+ actual++;
-+ }
-+
-+ return actual;
-+}
-+
-+
-+static void btuart_write_wakeup(btuart_info_t *info)
-+{
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ return;
-+
-+ if (!(skb = skb_dequeue(&(info->txq))))
-+ break;
-+
-+ /* Send frame */
-+ len = btuart_write(iobase, 16, skb->data, skb->len);
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (len == skb->len) {
-+ kfree_skb(skb);
-+ } else {
-+ skb_pull(skb, len);
-+ skb_queue_head(&(info->txq), skb);
-+ }
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static void btuart_receive(btuart_info_t *info)
-+{
-+ unsigned int iobase;
-+ int boguscount = 0;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ do {
-+ info->hdev.stat.byte_rx++;
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL) {
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
-+ return;
-+ }
-+ }
-+
-+ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type = inb(iobase + UART_RX);
-+
-+ switch (info->rx_skb->pkt_type) {
-+
-+ case HCI_EVENT_PKT:
-+ info->rx_state = RECV_WAIT_EVENT_HEADER;
-+ info->rx_count = HCI_EVENT_HDR_SIZE;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ info->rx_state = RECV_WAIT_ACL_HEADER;
-+ info->rx_count = HCI_ACL_HDR_SIZE;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ info->rx_state = RECV_WAIT_SCO_HEADER;
-+ info->rx_count = HCI_SCO_HDR_SIZE;
-+ break;
-+
-+ default:
-+ /* Unknown packet */
-+ printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ info->hdev.stat.err_rx++;
-+ clear_bit(HCI_RUNNING, &(info->hdev.flags));
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ } else {
-+
-+ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ int dlen;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+
-+
-+ switch (info->rx_state) {
-+
-+ case RECV_WAIT_EVENT_HEADER:
-+ eh = (hci_event_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = eh->plen;
-+ break;
-+
-+ case RECV_WAIT_ACL_HEADER:
-+ ah = (hci_acl_hdr *)(info->rx_skb->data);
-+ dlen = __le16_to_cpu(ah->dlen);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = dlen;
-+ break;
-+
-+ case RECV_WAIT_SCO_HEADER:
-+ sh = (hci_sco_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = sh->dlen;
-+ break;
-+
-+ case RECV_WAIT_DATA:
-+ hci_recv_frame(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 16)
-+ break;
-+
-+ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-+}
-+
-+
-+void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ btuart_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ int boguscount = 0;
-+ int iir, lsr;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+ while (iir) {
-+
-+ /* Clear interrupt */
-+ lsr = inb(iobase + UART_LSR);
-+
-+ switch (iir) {
-+ case UART_IIR_RLSI:
-+ printk(KERN_NOTICE "btuart_cs: RLSI\n");
-+ break;
-+ case UART_IIR_RDI:
-+ /* Receive interrupt */
-+ btuart_receive(info);
-+ break;
-+ case UART_IIR_THRI:
-+ if (lsr & UART_LSR_THRE) {
-+ /* Transmitter ready for data */
-+ btuart_write_wakeup(info);
-+ }
-+ break;
-+ default:
-+ printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
-+ break;
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 100)
-+ break;
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+
-+ }
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
-+{
-+ unsigned long flags;
-+ unsigned int iobase;
-+ int fcr; /* FIFO control reg */
-+ int lcr; /* Line control reg */
-+ int divisor;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ divisor = SPEED_MAX / speed;
-+
-+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
-+
-+ /*
-+ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
-+ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
-+ * about this timeout since it will always be fast enough.
-+ */
-+
-+ if (speed < 38400)
-+ fcr |= UART_FCR_TRIGGER_1;
-+ else
-+ fcr |= UART_FCR_TRIGGER_14;
-+
-+ /* Bluetooth cards use 8N1 */
-+ lcr = UART_LCR_WLEN8;
-+
-+ outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
-+ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
-+ outb(divisor >> 8, iobase + UART_DLM);
-+ outb(lcr, iobase + UART_LCR); /* Set 8N1 */
-+ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
-+
-+ /* Turn on interrups */
-+ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int btuart_hci_flush(struct hci_dev *hdev)
-+{
-+ btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int btuart_hci_open(struct hci_dev *hdev)
-+{
-+ set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+ return 0;
-+}
-+
-+
-+static int btuart_hci_close(struct hci_dev *hdev)
-+{
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ btuart_hci_flush(hdev);
-+
-+ return 0;
-+}
-+
-+
-+static int btuart_hci_send_frame(struct sk_buff *skb)
-+{
-+ btuart_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (btuart_info_t *)(hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ btuart_write_wakeup(info);
-+
-+ return 0;
-+}
-+
-+
-+static void btuart_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int btuart_open(btuart_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ info->rx_skb = NULL;
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ /* Initialize UART */
-+ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
-+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-+
-+ /* Turn on interrupts */
-+ // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ btuart_change_speed(info, DEFAULT_BAUD_RATE);
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ);
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = btuart_hci_open;
-+ hdev->close = btuart_hci_close;
-+ hdev->flush = btuart_hci_flush;
-+ hdev->send = btuart_hci_send_frame;
-+ hdev->destruct = btuart_hci_destruct;
-+ hdev->ioctl = btuart_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int btuart_close(btuart_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
-+ btuart_hci_close(hdev);
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *btuart_attach(void)
-+{
-+ btuart_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &btuart_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = btuart_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &btuart_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ btuart_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void btuart_detach(dev_link_t *link)
-+{
-+ btuart_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+ if (link->state & DEV_CONFIG)
-+ btuart_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void btuart_config(dev_link_t *link)
-+{
-+ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-+ client_handle_t handle = link->handle;
-+ btuart_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
-+ int i, j, try, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ /* First pass: look for a config entry that looks normal. */
-+ tuple.TupleData = (cisdata_t *) buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+ /* Two tries: without IO aliases, then with aliases */
-+ for (try = 0; try < 2; try++) {
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if (i != CS_SUCCESS)
-+ goto next_entry;
-+ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-+ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-+ link->conf.ConfigIndex = cf->index;
-+ link->io.BasePort1 = cf->io.win[0].base;
-+ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+next_entry:
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+ }
-+
-+ /* Second pass: try to find an entry that isn't picky about
-+ its base address, then try to grab any standard serial port
-+ address, and finally try to get any free port. */
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
-+ && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-+ link->conf.ConfigIndex = cf->index;
-+ for (j = 0; j < 5; j++) {
-+ link->io.BasePort1 = base[j];
-+ link->io.IOAddrLines = base[j] ? 16 : 3;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+ }
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+
-+found_port:
-+ if (i != CS_SUCCESS) {
-+ printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (btuart_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ btuart_release((u_long) link);
-+}
-+
-+
-+void btuart_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ btuart_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ btuart_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int btuart_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ btuart_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ btuart_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ btuart_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_btuart_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_btuart_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ btuart_detach(dev_list);
-+}
-+
-+
-+module_init(init_btuart_cs);
-+module_exit(exit_btuart_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/Config.in linux-2.4.18-mh15/drivers/bluetooth/Config.in
---- linux-2.4.18/drivers/bluetooth/Config.in 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/bluetooth/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -1,8 +1,33 @@
-+#
-+# Bluetooth HCI device drivers configuration
-+#
-+
- mainmenu_option next_comment
- comment 'Bluetooth device drivers'
-
- dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
-+if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
-+ bool ' SCO (voice) support' CONFIG_BLUEZ_HCIUSB_SCO
-+fi
-+
- dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
--dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
-+if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
-+ bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
-+ bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
-+ dep_bool ' Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
-+fi
-+
-+dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB
-+
-+dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
-
- endmenu
-+
-diff -urN linux-2.4.18/drivers/bluetooth/dtl1_cs.c linux-2.4.18-mh15/drivers/bluetooth/dtl1_cs.c
---- linux-2.4.18/drivers/bluetooth/dtl1_cs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/dtl1_cs.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,861 @@
-+/*
-+ *
-+ * A driver for Nokia Connectivity Card DTL-1 devices
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct dtl1_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+
-+ unsigned long flowmask; /* HCI flow mask */
-+ int ri_latch;
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+} dtl1_info_t;
-+
-+
-+void dtl1_config(dev_link_t *link);
-+void dtl1_release(u_long arg);
-+int dtl1_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "dtl1_cs";
-+
-+dev_link_t *dtl1_attach(void);
-+void dtl1_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_WAITING 8
-+
-+/* Receiver States */
-+#define RECV_WAIT_NSH 0
-+#define RECV_WAIT_DATA 1
-+
-+
-+typedef struct {
-+ u8 type;
-+ u8 zero;
-+ u16 len;
-+} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */
-+
-+#define NSHL 4 /* Nokia Specific Header Length */
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+ int actual = 0;
-+
-+ /* Tx FIFO should be empty */
-+ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-+ return 0;
-+
-+ /* Fill FIFO with current frame */
-+ while ((fifo_size-- > 0) && (actual < len)) {
-+ /* Transmit next byte */
-+ outb(buf[actual], iobase + UART_TX);
-+ actual++;
-+ }
-+
-+ return actual;
-+}
-+
-+
-+static void dtl1_write_wakeup(dtl1_info_t *info)
-+{
-+ if (!info) {
-+ printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (test_bit(XMIT_WAITING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ return;
-+
-+ if (!(skb = skb_dequeue(&(info->txq))))
-+ break;
-+
-+ /* Send frame */
-+ len = dtl1_write(iobase, 32, skb->data, skb->len);
-+
-+ if (len == skb->len) {
-+ set_bit(XMIT_WAITING, &(info->tx_state));
-+ kfree_skb(skb);
-+ } else {
-+ skb_pull(skb, len);
-+ skb_queue_head(&(info->txq), skb);
-+ }
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
-+{
-+ u8 flowmask = *(u8 *)skb->data;
-+ int i;
-+
-+ printk(KERN_INFO "dtl1_cs: Nokia control data = ");
-+ for (i = 0; i < skb->len; i++) {
-+ printk("%02x ", skb->data[i]);
-+ }
-+ printk("\n");
-+
-+ /* transition to active state */
-+ if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
-+ clear_bit(XMIT_WAITING, &(info->tx_state));
-+ dtl1_write_wakeup(info);
-+ }
-+
-+ info->flowmask = flowmask;
-+
-+ kfree_skb(skb);
-+}
-+
-+
-+static void dtl1_receive(dtl1_info_t *info)
-+{
-+ unsigned int iobase;
-+ nsh_t *nsh;
-+ int boguscount = 0;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ do {
-+ info->hdev.stat.byte_rx++;
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL)
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
-+ info->rx_state = RECV_WAIT_NSH;
-+ info->rx_count = NSHL;
-+ return;
-+ }
-+
-+ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-+ nsh = (nsh_t *)info->rx_skb->data;
-+
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ switch (info->rx_state) {
-+ case RECV_WAIT_NSH:
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = nsh->len + (nsh->len & 0x0001);
-+ break;
-+ case RECV_WAIT_DATA:
-+ info->rx_skb->pkt_type = nsh->type;
-+
-+ /* remove PAD byte if it exists */
-+ if (nsh->len & 0x0001) {
-+ info->rx_skb->tail--;
-+ info->rx_skb->len--;
-+ }
-+
-+ /* remove NSH */
-+ skb_pull(info->rx_skb, NSHL);
-+
-+ switch (info->rx_skb->pkt_type) {
-+ case 0x80:
-+ /* control data for the Nokia Card */
-+ dtl1_control(info, info->rx_skb);
-+ break;
-+ case 0x82:
-+ case 0x83:
-+ case 0x84:
-+ /* send frame to the HCI layer */
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type &= 0x0f;
-+ hci_recv_frame(info->rx_skb);
-+ break;
-+ default:
-+ /* unknown packet */
-+ printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ kfree_skb(info->rx_skb);
-+ break;
-+ }
-+
-+ info->rx_state = RECV_WAIT_NSH;
-+ info->rx_count = NSHL;
-+ info->rx_skb = NULL;
-+ break;
-+ }
-+
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 32)
-+ break;
-+
-+ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-+}
-+
-+
-+void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ dtl1_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ unsigned char msr;
-+ int boguscount = 0;
-+ int iir, lsr;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+ while (iir) {
-+
-+ /* Clear interrupt */
-+ lsr = inb(iobase + UART_LSR);
-+
-+ switch (iir) {
-+ case UART_IIR_RLSI:
-+ printk(KERN_NOTICE "dtl1_cs: RLSI\n");
-+ break;
-+ case UART_IIR_RDI:
-+ /* Receive interrupt */
-+ dtl1_receive(info);
-+ break;
-+ case UART_IIR_THRI:
-+ if (lsr & UART_LSR_THRE) {
-+ /* Transmitter ready for data */
-+ dtl1_write_wakeup(info);
-+ }
-+ break;
-+ default:
-+ printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
-+ break;
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 100)
-+ break;
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+
-+ }
-+
-+ msr = inb(iobase + UART_MSR);
-+
-+ if (info->ri_latch ^ (msr & UART_MSR_RI)) {
-+ info->ri_latch = msr & UART_MSR_RI;
-+ clear_bit(XMIT_WAITING, &(info->tx_state));
-+ dtl1_write_wakeup(info);
-+ }
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int dtl1_hci_open(struct hci_dev *hdev)
-+{
-+ set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+ return 0;
-+}
-+
-+
-+static int dtl1_hci_flush(struct hci_dev *hdev)
-+{
-+ dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int dtl1_hci_close(struct hci_dev *hdev)
-+{
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ dtl1_hci_flush(hdev);
-+
-+ return 0;
-+}
-+
-+
-+static int dtl1_hci_send_frame(struct sk_buff *skb)
-+{
-+ dtl1_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+ struct sk_buff *s;
-+ nsh_t nsh;
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (dtl1_info_t *)(hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ nsh.type = 0x81;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ nsh.type = 0x82;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ nsh.type = 0x83;
-+ break;
-+ };
-+
-+ nsh.zero = 0;
-+ nsh.len = skb->len;
-+
-+ s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
-+ skb_reserve(s, NSHL);
-+ memcpy(skb_put(s, skb->len), skb->data, skb->len);
-+ if (skb->len & 0x0001)
-+ *skb_put(s, 1) = 0; /* PAD */
-+
-+ /* Prepend skb with Nokia frame header and queue */
-+ memcpy(skb_push(s, NSHL), &nsh, NSHL);
-+ skb_queue_tail(&(info->txq), s);
-+
-+ dtl1_write_wakeup(info);
-+
-+ kfree_skb(skb);
-+
-+ return 0;
-+}
-+
-+
-+static void dtl1_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int dtl1_open(dtl1_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_NSH;
-+ info->rx_count = NSHL;
-+ info->rx_skb = NULL;
-+
-+ set_bit(XMIT_WAITING, &(info->tx_state));
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ /* Initialize UART */
-+ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
-+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-+
-+ info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
-+
-+ /* Turn on interrupts */
-+ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ * 2);
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = dtl1_hci_open;
-+ hdev->close = dtl1_hci_close;
-+ hdev->flush = dtl1_hci_flush;
-+ hdev->send = dtl1_hci_send_frame;
-+ hdev->destruct = dtl1_hci_destruct;
-+ hdev->ioctl = dtl1_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int dtl1_close(dtl1_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ if (info->link.state & DEV_CONFIG_PENDING)
-+ return -ENODEV;
-+
-+ dtl1_hci_close(hdev);
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *dtl1_attach(void)
-+{
-+ dtl1_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &dtl1_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = dtl1_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &dtl1_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ dtl1_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void dtl1_detach(dev_link_t *link)
-+{
-+ dtl1_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+ if (link->state & DEV_CONFIG)
-+ dtl1_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void dtl1_config(dev_link_t *link)
-+{
-+ client_handle_t handle = link->handle;
-+ dtl1_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
-+ int i, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+
-+ /* Look for a generic full-sized window */
-+ link->io.NumPorts1 = 8;
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-+ link->conf.ConfigIndex = cf->index;
-+ link->io.BasePort1 = cf->io.win[0].base;
-+ link->io.NumPorts1 = cf->io.win[0].len; /*yo */
-+ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ break;
-+ }
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (dtl1_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ dtl1_release((u_long)link);
-+}
-+
-+
-+void dtl1_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ dtl1_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ dtl1_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int dtl1_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ dtl1_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ dtl1_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ dtl1_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_dtl1_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_dtl1_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ dtl1_detach(dev_list);
-+}
-+
-+
-+module_init(init_dtl1_cs);
-+module_exit(exit_dtl1_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.c linux-2.4.18-mh15/drivers/bluetooth/hci_bcsp.c
---- linux-2.4.18/drivers/bluetooth/hci_bcsp.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_bcsp.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,710 @@
-+/*
-+ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
-+ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
-+
-+ Based on
-+ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com>
-+ ABCSP by Carl Orsborn <cjo@csr.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#define VERSION "0.1"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/fcntl.h>
-+#include <linux/interrupt.h>
-+#include <linux/ptrace.h>
-+#include <linux/poll.h>
-+
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/signal.h>
-+#include <linux/ioctl.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_uart.h"
-+#include "hci_bcsp.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+/* ---- BCSP CRC calculation ---- */
-+
-+/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
-+initial value 0xffff, bits shifted in reverse order. */
-+
-+static const u16 crc_table[] = {
-+ 0x0000, 0x1081, 0x2102, 0x3183,
-+ 0x4204, 0x5285, 0x6306, 0x7387,
-+ 0x8408, 0x9489, 0xa50a, 0xb58b,
-+ 0xc60c, 0xd68d, 0xe70e, 0xf78f
-+};
-+
-+/* Initialise the crc calculator */
-+#define BCSP_CRC_INIT(x) x = 0xffff
-+
-+/*
-+ Update crc with next data byte
-+
-+ Implementation note
-+ The data byte is treated as two nibbles. The crc is generated
-+ in reverse, i.e., bits are fed into the register from the top.
-+*/
-+static void bcsp_crc_update(u16 *crc, u8 d)
-+{
-+ u16 reg = *crc;
-+
-+ reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
-+ reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
-+
-+ *crc = reg;
-+}
-+
-+/*
-+ Get reverse of generated crc
-+
-+ Implementation note
-+ The crc generator (bcsp_crc_init() and bcsp_crc_update())
-+ creates a reversed crc, so it needs to be swapped back before
-+ being passed on.
-+*/
-+static u16 bcsp_crc_reverse(u16 crc)
-+{
-+ u16 b, rev;
-+
-+ for (b = 0, rev = 0; b < 16; b++) {
-+ rev = rev << 1;
-+ rev |= (crc & 1);
-+ crc = crc >> 1;
-+ }
-+ return (rev);
-+}
-+
-+/* ---- BCSP core ---- */
-+
-+static void bcsp_slip_msgdelim(struct sk_buff *skb)
-+{
-+ const char pkt_delim = 0xc0;
-+ memcpy(skb_put(skb, 1), &pkt_delim, 1);
-+}
-+
-+static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
-+{
-+ const char esc_c0[2] = { 0xdb, 0xdc };
-+ const char esc_db[2] = { 0xdb, 0xdd };
-+
-+ switch (c) {
-+ case 0xc0:
-+ memcpy(skb_put(skb, 2), &esc_c0, 2);
-+ break;
-+ case 0xdb:
-+ memcpy(skb_put(skb, 2), &esc_db, 2);
-+ break;
-+ default:
-+ memcpy(skb_put(skb, 1), &c, 1);
-+ }
-+}
-+
-+static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+
-+ if (skb->len > 0xFFF) {
-+ BT_ERR("Packet too long");
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+
-+ switch (skb->pkt_type) {
-+ case HCI_ACLDATA_PKT:
-+ case HCI_COMMAND_PKT:
-+ skb_queue_tail(&bcsp->rel, skb);
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ skb_queue_tail(&bcsp->unrel, skb);
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown packet type");
-+ kfree_skb(skb);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
-+ int len, int pkt_type)
-+{
-+ struct sk_buff *nskb;
-+ u8 hdr[4], chan;
-+ int rel, i;
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
-+#endif
-+
-+ switch (pkt_type) {
-+ case HCI_ACLDATA_PKT:
-+ chan = 6; /* BCSP ACL channel */
-+ rel = 1; /* reliable channel */
-+ break;
-+ case HCI_COMMAND_PKT:
-+ chan = 5; /* BCSP cmd/evt channel */
-+ rel = 1; /* reliable channel */
-+ break;
-+ case HCI_SCODATA_PKT:
-+ chan = 7; /* BCSP SCO channel */
-+ rel = 0; /* unreliable channel */
-+ break;
-+ case BCSP_LE_PKT:
-+ chan = 1; /* BCSP LE channel */
-+ rel = 0; /* unreliable channel */
-+ break;
-+ case BCSP_ACK_PKT:
-+ chan = 0; /* BCSP internal channel */
-+ rel = 0; /* unreliable channel */
-+ break;
-+ default:
-+ BT_ERR("Unknown packet type");
-+ return NULL;
-+ }
-+
-+ /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
-+ (because bytes 0xc0 and 0xdb are escaped, worst case is
-+ when the packet is all made of 0xc0 and 0xdb :) )
-+ + 2 (0xc0 delimiters at start and end). */
-+
-+ nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
-+ if (!nskb)
-+ return NULL;
-+
-+ nskb->pkt_type = pkt_type;
-+
-+ bcsp_slip_msgdelim(nskb);
-+
-+ hdr[0] = bcsp->rxseq_txack << 3;
-+ bcsp->txack_req = 0;
-+ BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
-+
-+ if (rel) {
-+ hdr[0] |= 0x80 + bcsp->msgq_txseq;
-+ BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
-+ bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
-+ }
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ hdr[0] |= 0x40;
-+#endif
-+
-+ hdr[1] = (len << 4) & 0xFF;
-+ hdr[1] |= chan;
-+ hdr[2] = len >> 4;
-+ hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]);
-+
-+ /* Put BCSP header */
-+ for (i = 0; i < 4; i++) {
-+ bcsp_slip_one_byte(nskb, hdr[i]);
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
-+#endif
-+ }
-+
-+ /* Put payload */
-+ for (i = 0; i < len; i++) {
-+ bcsp_slip_one_byte(nskb, data[i]);
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
-+#endif
-+ }
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ /* Put CRC */
-+ bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
-+ bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
-+ bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
-+#endif
-+
-+ bcsp_slip_msgdelim(nskb);
-+ return nskb;
-+}
-+
-+/* This is a rewrite of pkt_avail in ABCSP */
-+static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
-+ unsigned long flags;
-+ struct sk_buff *skb;
-+
-+ /* First of all, check for unreliable messages in the queue,
-+ since they have priority */
-+
-+ if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
-+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
-+ if (nskb) {
-+ kfree_skb(skb);
-+ return nskb;
-+ } else {
-+ skb_queue_head(&bcsp->unrel, skb);
-+ BT_ERR("Could not dequeue pkt because alloc_skb failed");
-+ }
-+ }
-+
-+ /* Now, try to send a reliable pkt. We can only send a
-+ reliable packet if the number of packets sent but not yet ack'ed
-+ is < than the winsize */
-+
-+ spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+ if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
-+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
-+ if (nskb) {
-+ __skb_queue_tail(&bcsp->unack, skb);
-+ mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+ return nskb;
-+ } else {
-+ skb_queue_head(&bcsp->rel, skb);
-+ BT_ERR("Could not dequeue pkt because alloc_skb failed");
-+ }
-+ }
-+
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+
-+ /* We could not send a reliable packet, either because there are
-+ none or because there are too many unack'ed pkts. Did we receive
-+ any packets we have not acknowledged yet ? */
-+
-+ if (bcsp->txack_req) {
-+ /* if so, craft an empty ACK pkt and send it on BCSP unreliable
-+ channel 0 */
-+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
-+ return nskb;
-+ }
-+
-+ /* We have nothing to send */
-+ return NULL;
-+}
-+
-+static int bcsp_flush(struct hci_uart *hu)
-+{
-+ BT_DBG("hu %p", hu);
-+ return 0;
-+}
-+
-+/* Remove ack'ed packets */
-+static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
-+{
-+ unsigned long flags;
-+ struct sk_buff *skb;
-+ int i, pkts_to_be_removed;
-+ u8 seqno;
-+
-+ spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+ pkts_to_be_removed = bcsp->unack.qlen;
-+ seqno = bcsp->msgq_txseq;
-+
-+ while (pkts_to_be_removed) {
-+ if (bcsp->rxack == seqno)
-+ break;
-+ pkts_to_be_removed--;
-+ seqno = (seqno - 1) & 0x07;
-+ }
-+
-+ if (bcsp->rxack != seqno)
-+ BT_ERR("Peer acked invalid packet");
-+
-+ BT_DBG("Removing %u pkts out of %u, up to seqno %u",
-+ pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
-+
-+ for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
-+ && skb != (struct sk_buff *) &bcsp->unack; i++) {
-+ struct sk_buff *nskb;
-+
-+ nskb = skb->next;
-+ __skb_unlink(skb, &bcsp->unack);
-+ kfree_skb(skb);
-+ skb = nskb;
-+ }
-+ if (bcsp->unack.qlen == 0)
-+ del_timer(&bcsp->tbcsp);
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+ if (i != pkts_to_be_removed)
-+ BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
-+}
-+
-+/* Handle BCSP link-establishment packets. When we
-+ detect a "sync" packet, symptom that the BT module has reset,
-+ we do nothing :) (yet) */
-+static void bcsp_handle_le_pkt(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed };
-+ u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
-+ u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed };
-+
-+ /* spot "conf" pkts and reply with a "conf rsp" pkt */
-+ if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
-+ !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
-+ struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
-+
-+ BT_DBG("Found a LE conf pkt");
-+ if (!nskb)
-+ return;
-+ memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
-+ nskb->pkt_type = BCSP_LE_PKT;
-+
-+ skb_queue_head(&bcsp->unrel, nskb);
-+ hci_uart_tx_wakeup(hu);
-+ }
-+ /* Spot "sync" pkts. If we find one...disaster! */
-+ else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
-+ !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
-+ BT_ERR("Found a LE sync pkt, card has reset");
-+ }
-+}
-+
-+static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
-+{
-+ const u8 c0 = 0xc0, db = 0xdb;
-+
-+ switch (bcsp->rx_esc_state) {
-+ case BCSP_ESCSTATE_NOESC:
-+ switch (byte) {
-+ case 0xdb:
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
-+ break;
-+ default:
-+ memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
-+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
-+ bcsp->rx_state != BCSP_W4_CRC)
-+ bcsp_crc_update(&bcsp->message_crc, byte);
-+ bcsp->rx_count--;
-+ }
-+ break;
-+
-+ case BCSP_ESCSTATE_ESC:
-+ switch (byte) {
-+ case 0xdc:
-+ memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
-+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
-+ bcsp->rx_state != BCSP_W4_CRC)
-+ bcsp_crc_update(&bcsp-> message_crc, 0xc0);
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+ bcsp->rx_count--;
-+ break;
-+
-+ case 0xdd:
-+ memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
-+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
-+ bcsp->rx_state != BCSP_W4_CRC)
-+ bcsp_crc_update(&bcsp-> message_crc, 0xdb);
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+ bcsp->rx_count--;
-+ break;
-+
-+ default:
-+ BT_ERR ("Invalid byte %02x after esc byte", byte);
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_skb = NULL;
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ }
-+ }
-+}
-+
-+static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ int pass_up;
-+
-+ if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */
-+ BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
-+ bcsp->rxseq_txack++;
-+ bcsp->rxseq_txack %= 0x8;
-+ bcsp->txack_req = 1;
-+
-+ /* If needed, transmit an ack pkt */
-+ hci_uart_tx_wakeup(hu);
-+ }
-+
-+ bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
-+ BT_DBG("Request for pkt %u from card", bcsp->rxack);
-+
-+ bcsp_pkt_cull(bcsp);
-+ if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
-+ bcsp->rx_skb->data[0] & 0x80) {
-+ bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
-+ pass_up = 1;
-+ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
-+ bcsp->rx_skb->data[0] & 0x80) {
-+ bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
-+ pass_up = 1;
-+ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
-+ bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
-+ pass_up = 1;
-+ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
-+ !(bcsp->rx_skb->data[0] & 0x80)) {
-+ bcsp_handle_le_pkt(hu);
-+ pass_up = 0;
-+ } else
-+ pass_up = 0;
-+
-+ if (!pass_up) {
-+ if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
-+ (bcsp->rx_skb->data[1] & 0x0f) != 1) {
-+ BT_ERR ("Packet for unknown channel (%u %s)",
-+ bcsp->rx_skb->data[1] & 0x0f,
-+ bcsp->rx_skb->data[0] & 0x80 ?
-+ "reliable" : "unreliable");
-+ }
-+ kfree_skb(bcsp->rx_skb);
-+ } else {
-+ /* Pull out BCSP hdr */
-+ skb_pull(bcsp->rx_skb, 4);
-+
-+ hci_recv_frame(bcsp->rx_skb);
-+ }
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_skb = NULL;
-+}
-+
-+/* Recv data */
-+static int bcsp_recv(struct hci_uart *hu, void *data, int count)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ register unsigned char *ptr;
-+
-+ BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
-+ hu, count, bcsp->rx_state, bcsp->rx_count);
-+
-+ ptr = data;
-+ while (count) {
-+ if (bcsp->rx_count) {
-+ if (*ptr == 0xc0) {
-+ BT_ERR("Short BCSP packet");
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_START;
-+ bcsp->rx_count = 0;
-+ } else
-+ bcsp_unslip_one_byte(bcsp, *ptr);
-+
-+ ptr++; count--;
-+ continue;
-+ }
-+
-+ switch (bcsp->rx_state) {
-+ case BCSP_W4_BCSP_HDR:
-+ if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
-+ bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
-+ BT_ERR("Error in BCSP hdr checksum");
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ continue;
-+ }
-+ if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */
-+ && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
-+ BT_ERR ("Out-of-order packet arrived, got %u expected %u",
-+ bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
-+
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ continue;
-+ }
-+ bcsp->rx_state = BCSP_W4_DATA;
-+ bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) +
-+ (bcsp->rx_skb->data[2] << 4); /* May be 0 */
-+ continue;
-+
-+ case BCSP_W4_DATA:
-+ if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */
-+ bcsp->rx_state = BCSP_W4_CRC;
-+ bcsp->rx_count = 2;
-+ } else
-+ bcsp_complete_rx_pkt(hu);
-+ continue;
-+
-+ case BCSP_W4_CRC:
-+ if (bcsp_crc_reverse(bcsp->message_crc) !=
-+ (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
-+ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
-+
-+ BT_ERR ("Checksum failed: computed %04x received %04x",
-+ bcsp_crc_reverse(bcsp->message_crc),
-+ (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
-+ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
-+
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ continue;
-+ }
-+ skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
-+ bcsp_complete_rx_pkt(hu);
-+ continue;
-+
-+ case BCSP_W4_PKT_DELIMITER:
-+ switch (*ptr) {
-+ case 0xc0:
-+ bcsp->rx_state = BCSP_W4_PKT_START;
-+ break;
-+ default:
-+ /*BT_ERR("Ignoring byte %02x", *ptr);*/
-+ break;
-+ }
-+ ptr++; count--;
-+ break;
-+
-+ case BCSP_W4_PKT_START:
-+ switch (*ptr) {
-+ case 0xc0:
-+ ptr++; count--;
-+ break;
-+
-+ default:
-+ bcsp->rx_state = BCSP_W4_BCSP_HDR;
-+ bcsp->rx_count = 4;
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+ BCSP_CRC_INIT(bcsp->message_crc);
-+
-+ /* Do not increment ptr or decrement count
-+ * Allocate packet. Max len of a BCSP pkt=
-+ * 0xFFF (payload) +4 (header) +2 (crc) */
-+
-+ bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
-+ if (!bcsp->rx_skb) {
-+ BT_ERR("Can't allocate mem for new packet");
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ return 0;
-+ }
-+ bcsp->rx_skb->dev = (void *) &hu->hdev;
-+ break;
-+ }
-+ break;
-+ }
-+ }
-+ return count;
-+}
-+
-+ /* Arrange to retransmit all messages in the relq. */
-+static void bcsp_timed_event(unsigned long arg)
-+{
-+ struct hci_uart *hu = (struct hci_uart *) arg;
-+ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
-+ struct sk_buff *skb;
-+ unsigned long flags;
-+
-+ BT_DBG("hu %p retransmitting %u pkts", hu, bcsp->unack.qlen);
-+
-+ spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+ while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
-+ bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
-+ skb_queue_head(&bcsp->rel, skb);
-+ }
-+
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+ hci_uart_tx_wakeup(hu);
-+}
-+
-+static int bcsp_open(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
-+ if (!bcsp)
-+ return -ENOMEM;
-+ memset(bcsp, 0, sizeof(*bcsp));
-+
-+ hu->priv = bcsp;
-+ skb_queue_head_init(&bcsp->unack);
-+ skb_queue_head_init(&bcsp->rel);
-+ skb_queue_head_init(&bcsp->unrel);
-+
-+ init_timer(&bcsp->tbcsp);
-+ bcsp->tbcsp.function = bcsp_timed_event;
-+ bcsp->tbcsp.data = (u_long) hu;
-+
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+
-+ return 0;
-+}
-+
-+static int bcsp_close(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ hu->priv = NULL;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ skb_queue_purge(&bcsp->unack);
-+ skb_queue_purge(&bcsp->rel);
-+ skb_queue_purge(&bcsp->unrel);
-+ del_timer(&bcsp->tbcsp);
-+
-+ kfree(bcsp);
-+ return 0;
-+}
-+
-+static struct hci_uart_proto bcsp = {
-+ id: HCI_UART_BCSP,
-+ open: bcsp_open,
-+ close: bcsp_close,
-+ enqueue: bcsp_enqueue,
-+ dequeue: bcsp_dequeue,
-+ recv: bcsp_recv,
-+ flush: bcsp_flush
-+};
-+
-+int bcsp_init(void)
-+{
-+ return hci_uart_register_proto(&bcsp);
-+}
-+
-+int bcsp_deinit(void)
-+{
-+ return hci_uart_unregister_proto(&bcsp);
-+}
-diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.h linux-2.4.18-mh15/drivers/bluetooth/hci_bcsp.h
---- linux-2.4.18/drivers/bluetooth/hci_bcsp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_bcsp.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,70 @@
-+/*
-+ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
-+ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
-+
-+ Based on
-+ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com>
-+ ABCSP by Carl Orsborn <cjo@csr.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __HCI_BCSP_H__
-+#define __HCI_BCSP_H__
-+
-+#define BCSP_TXWINSIZE 4
-+
-+#define BCSP_ACK_PKT 0x05
-+#define BCSP_LE_PKT 0x06
-+
-+struct bcsp_struct {
-+ struct sk_buff_head unack; /* Unack'ed packets queue */
-+ struct sk_buff_head rel; /* Reliable packets queue */
-+ struct sk_buff_head unrel; /* Unreliable packets queue */
-+
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+ u8 rxseq_txack; /* rxseq == txack. */
-+ u8 rxack; /* Last packet sent by us that the peer ack'ed */
-+ struct timer_list tbcsp;
-+
-+ enum {
-+ BCSP_W4_PKT_DELIMITER,
-+ BCSP_W4_PKT_START,
-+ BCSP_W4_BCSP_HDR,
-+ BCSP_W4_DATA,
-+ BCSP_W4_CRC
-+ } rx_state;
-+
-+ enum {
-+ BCSP_ESCSTATE_NOESC,
-+ BCSP_ESCSTATE_ESC
-+ } rx_esc_state;
-+
-+ u16 message_crc;
-+ u8 txack_req; /* Do we need to send ack's to the peer? */
-+
-+ /* Reliable packet sequence number - used to assign seq to each rel pkt. */
-+ u8 msgq_txseq;
-+};
-+
-+#endif /* __HCI_BCSP_H__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.c linux-2.4.18-mh15/drivers/bluetooth/hci_h4.c
---- linux-2.4.18/drivers/bluetooth/hci_h4.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_h4.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,277 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ HCI UART(H4) protocol.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "1.2"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/fcntl.h>
-+#include <linux/interrupt.h>
-+#include <linux/ptrace.h>
-+#include <linux/poll.h>
-+
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/signal.h>
-+#include <linux/ioctl.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_uart.h"
-+#include "hci_h4.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+/* Initialize protocol */
-+static int h4_open(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
-+ if (!h4)
-+ return -ENOMEM;
-+ memset(h4, 0, sizeof(*h4));
-+
-+ skb_queue_head_init(&h4->txq);
-+
-+ hu->priv = h4;
-+ return 0;
-+}
-+
-+/* Flush protocol data */
-+static int h4_flush(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+
-+ BT_DBG("hu %p", hu);
-+ skb_queue_purge(&h4->txq);
-+ return 0;
-+}
-+
-+/* Close protocol */
-+static int h4_close(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+ hu->priv = NULL;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ skb_queue_purge(&h4->txq);
-+ if (h4->rx_skb)
-+ kfree_skb(h4->rx_skb);
-+
-+ hu->priv = NULL;
-+ kfree(h4);
-+ return 0;
-+}
-+
-+/* Enqueue frame for transmittion (padding, crc, etc) */
-+static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+
-+ BT_DBG("hu %p skb %p", hu, skb);
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-+ skb_queue_tail(&h4->txq, skb);
-+ return 0;
-+}
-+
-+static inline int h4_check_data_len(struct h4_struct *h4, int len)
-+{
-+ register int room = skb_tailroom(h4->rx_skb);
-+
-+ BT_DBG("len %d room %d", len, room);
-+ if (!len) {
-+ BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
-+ hci_recv_frame(h4->rx_skb);
-+ } else if (len > room) {
-+ BT_ERR("Data length is too large");
-+ kfree_skb(h4->rx_skb);
-+ } else {
-+ h4->rx_state = H4_W4_DATA;
-+ h4->rx_count = len;
-+ return len;
-+ }
-+
-+ h4->rx_state = H4_W4_PACKET_TYPE;
-+ h4->rx_skb = NULL;
-+ h4->rx_count = 0;
-+ return 0;
-+}
-+
-+/* Recv data */
-+static int h4_recv(struct hci_uart *hu, void *data, int count)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+ register char *ptr;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+ register int len, type, dlen;
-+
-+ BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
-+ hu, count, h4->rx_state, h4->rx_count);
-+
-+ ptr = data;
-+ while (count) {
-+ if (h4->rx_count) {
-+ len = MIN(h4->rx_count, count);
-+ memcpy(skb_put(h4->rx_skb, len), ptr, len);
-+ h4->rx_count -= len; count -= len; ptr += len;
-+
-+ if (h4->rx_count)
-+ continue;
-+
-+ switch (h4->rx_state) {
-+ case H4_W4_DATA:
-+ BT_DBG("Complete data");
-+
-+ BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
-+
-+ hci_recv_frame(h4->rx_skb);
-+
-+ h4->rx_state = H4_W4_PACKET_TYPE;
-+ h4->rx_skb = NULL;
-+ continue;
-+
-+ case H4_W4_EVENT_HDR:
-+ eh = (hci_event_hdr *) h4->rx_skb->data;
-+
-+ BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
-+
-+ h4_check_data_len(h4, eh->plen);
-+ continue;
-+
-+ case H4_W4_ACL_HDR:
-+ ah = (hci_acl_hdr *) h4->rx_skb->data;
-+ dlen = __le16_to_cpu(ah->dlen);
-+
-+ BT_DBG("ACL header: dlen %d", dlen);
-+
-+ h4_check_data_len(h4, dlen);
-+ continue;
-+
-+ case H4_W4_SCO_HDR:
-+ sh = (hci_sco_hdr *) h4->rx_skb->data;
-+
-+ BT_DBG("SCO header: dlen %d", sh->dlen);
-+
-+ h4_check_data_len(h4, sh->dlen);
-+ continue;
-+ }
-+ }
-+
-+ /* H4_W4_PACKET_TYPE */
-+ switch (*ptr) {
-+ case HCI_EVENT_PKT:
-+ BT_DBG("Event packet");
-+ h4->rx_state = H4_W4_EVENT_HDR;
-+ h4->rx_count = HCI_EVENT_HDR_SIZE;
-+ type = HCI_EVENT_PKT;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ BT_DBG("ACL packet");
-+ h4->rx_state = H4_W4_ACL_HDR;
-+ h4->rx_count = HCI_ACL_HDR_SIZE;
-+ type = HCI_ACLDATA_PKT;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ BT_DBG("SCO packet");
-+ h4->rx_state = H4_W4_SCO_HDR;
-+ h4->rx_count = HCI_SCO_HDR_SIZE;
-+ type = HCI_SCODATA_PKT;
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-+ hu->hdev.stat.err_rx++;
-+ ptr++; count--;
-+ continue;
-+ };
-+ ptr++; count--;
-+
-+ /* Allocate packet */
-+ h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
-+ if (!h4->rx_skb) {
-+ BT_ERR("Can't allocate mem for new packet");
-+ h4->rx_state = H4_W4_PACKET_TYPE;
-+ h4->rx_count = 0;
-+ return 0;
-+ }
-+ h4->rx_skb->dev = (void *) &hu->hdev;
-+ h4->rx_skb->pkt_type = type;
-+ }
-+ return count;
-+}
-+
-+static struct sk_buff *h4_dequeue(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+ return skb_dequeue(&h4->txq);
-+}
-+
-+static struct hci_uart_proto h4p = {
-+ id: HCI_UART_H4,
-+ open: h4_open,
-+ close: h4_close,
-+ recv: h4_recv,
-+ enqueue: h4_enqueue,
-+ dequeue: h4_dequeue,
-+ flush: h4_flush,
-+};
-+
-+int h4_init(void)
-+{
-+ return hci_uart_register_proto(&h4p);
-+}
-+
-+int h4_deinit(void)
-+{
-+ return hci_uart_unregister_proto(&h4p);
-+}
-diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.h linux-2.4.18-mh15/drivers/bluetooth/hci_h4.h
---- linux-2.4.18/drivers/bluetooth/hci_h4.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_h4.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,44 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifdef __KERNEL__
-+struct h4_struct {
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+ struct sk_buff_head txq;
-+};
-+
-+/* H4 receiver States */
-+#define H4_W4_PACKET_TYPE 0
-+#define H4_W4_EVENT_HDR 1
-+#define H4_W4_ACL_HDR 2
-+#define H4_W4_SCO_HDR 3
-+#define H4_W4_DATA 4
-+
-+#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_ldisc.c linux-2.4.18-mh15/drivers/bluetooth/hci_ldisc.c
---- linux-2.4.18/drivers/bluetooth/hci_ldisc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_ldisc.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,579 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ HCI UART driver.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "2.1"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/fcntl.h>
-+#include <linux/interrupt.h>
-+#include <linux/ptrace.h>
-+#include <linux/poll.h>
-+
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/signal.h>
-+#include <linux/ioctl.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_uart.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
-+
-+int hci_uart_register_proto(struct hci_uart_proto *p)
-+{
-+ if (p->id >= HCI_UART_MAX_PROTO)
-+ return -EINVAL;
-+
-+ if (hup[p->id])
-+ return -EEXIST;
-+
-+ hup[p->id] = p;
-+ return 0;
-+}
-+
-+int hci_uart_unregister_proto(struct hci_uart_proto *p)
-+{
-+ if (p->id >= HCI_UART_MAX_PROTO)
-+ return -EINVAL;
-+
-+ if (!hup[p->id])
-+ return -EINVAL;
-+
-+ hup[p->id] = NULL;
-+ return 0;
-+}
-+
-+static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
-+{
-+ if (id >= HCI_UART_MAX_PROTO)
-+ return NULL;
-+ return hup[id];
-+}
-+
-+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
-+{
-+ struct hci_dev *hdev = &hu->hdev;
-+
-+ /* Update HCI stat counters */
-+ switch (pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ }
-+}
-+
-+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
-+{
-+ struct sk_buff *skb = hu->tx_skb;
-+ if (!skb)
-+ skb = hu->proto->dequeue(hu);
-+ else
-+ hu->tx_skb = NULL;
-+ return skb;
-+}
-+
-+int hci_uart_tx_wakeup(struct hci_uart *hu)
-+{
-+ struct tty_struct *tty = hu->tty;
-+ struct hci_dev *hdev = &hu->hdev;
-+ struct sk_buff *skb;
-+
-+ if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
-+ set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
-+ return 0;
-+ }
-+
-+ BT_DBG("");
-+
-+restart:
-+ clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
-+
-+ while ((skb = hci_uart_dequeue(hu))) {
-+ int len;
-+
-+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-+ len = tty->driver.write(tty, 0, skb->data, skb->len);
-+ hdev->stat.byte_tx += len;
-+
-+ skb_pull(skb, len);
-+ if (skb->len) {
-+ hu->tx_skb = skb;
-+ break;
-+ }
-+
-+ hci_uart_tx_complete(hu, skb->pkt_type);
-+ kfree_skb(skb);
-+ }
-+
-+ if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
-+ goto restart;
-+
-+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
-+ return 0;
-+}
-+
-+/* ------- Interface to HCI layer ------ */
-+/* Initialize device */
-+static int hci_uart_open(struct hci_dev *hdev)
-+{
-+ BT_DBG("%s %p", hdev->name, hdev);
-+
-+ /* Nothing to do for UART driver */
-+
-+ set_bit(HCI_RUNNING, &hdev->flags);
-+ return 0;
-+}
-+
-+/* Reset device */
-+static int hci_uart_flush(struct hci_dev *hdev)
-+{
-+ struct hci_uart *hu = (struct hci_uart *) hdev->driver_data;
-+ struct tty_struct *tty = hu->tty;
-+
-+ BT_DBG("hdev %p tty %p", hdev, tty);
-+
-+ if (hu->tx_skb) {
-+ kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
-+ }
-+
-+ /* Flush any pending characters in the driver and discipline. */
-+ if (tty->ldisc.flush_buffer)
-+ tty->ldisc.flush_buffer(tty);
-+
-+ if (tty->driver.flush_buffer)
-+ tty->driver.flush_buffer(tty);
-+
-+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ hu->proto->flush(hu);
-+
-+ return 0;
-+}
-+
-+/* Close device */
-+static int hci_uart_close(struct hci_dev *hdev)
-+{
-+ BT_DBG("hdev %p", hdev);
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ hci_uart_flush(hdev);
-+ return 0;
-+}
-+
-+/* Send frames from HCI layer */
-+static int hci_uart_send_frame(struct sk_buff *skb)
-+{
-+ struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-+ struct tty_struct *tty;
-+ struct hci_uart *hu;
-+
-+ if (!hdev) {
-+ BT_ERR("Frame for uknown device (hdev=NULL)");
-+ return -ENODEV;
-+ }
-+
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-+
-+ hu = (struct hci_uart *) hdev->driver_data;
-+ tty = hu->tty;
-+
-+ BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+
-+ hu->proto->enqueue(hu, skb);
-+
-+ hci_uart_tx_wakeup(hu);
-+ return 0;
-+}
-+
-+static void hci_uart_destruct(struct hci_dev *hdev)
-+{
-+ struct hci_uart *hu;
-+
-+ if (!hdev) return;
-+
-+ BT_DBG("%s", hdev->name);
-+
-+ hu = (struct hci_uart *) hdev->driver_data;
-+ kfree(hu);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* ------ LDISC part ------ */
-+/* hci_uart_tty_open
-+ *
-+ * Called when line discipline changed to HCI_UART.
-+ *
-+ * Arguments:
-+ * tty pointer to tty info structure
-+ * Return Value:
-+ * 0 if success, otherwise error code
-+ */
-+static int hci_uart_tty_open(struct tty_struct *tty)
-+{
-+ struct hci_uart *hu = (void *) tty->disc_data;
-+
-+ BT_DBG("tty %p", tty);
-+
-+ if (hu)
-+ return -EEXIST;
-+
-+ if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
-+ BT_ERR("Can't allocate controll structure");
-+ return -ENFILE;
-+ }
-+ memset(hu, 0, sizeof(struct hci_uart));
-+
-+ tty->disc_data = hu;
-+ hu->tty = tty;
-+
-+ spin_lock_init(&hu->rx_lock);
-+
-+ /* Flush any pending characters in the driver and line discipline */
-+ if (tty->ldisc.flush_buffer)
-+ tty->ldisc.flush_buffer(tty);
-+
-+ if (tty->driver.flush_buffer)
-+ tty->driver.flush_buffer(tty);
-+
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+/* hci_uart_tty_close()
-+ *
-+ * Called when the line discipline is changed to something
-+ * else, the tty is closed, or the tty detects a hangup.
-+ */
-+static void hci_uart_tty_close(struct tty_struct *tty)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+
-+ BT_DBG("tty %p", tty);
-+
-+ /* Detach from the tty */
-+ tty->disc_data = NULL;
-+
-+ if (hu) {
-+ struct hci_dev *hdev = &hu->hdev;
-+ hci_uart_close(hdev);
-+
-+ if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-+ hu->proto->close(hu);
-+ hci_unregister_dev(hdev);
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+ }
-+}
-+
-+/* hci_uart_tty_wakeup()
-+ *
-+ * Callback for transmit wakeup. Called when low level
-+ * device driver can accept more send data.
-+ *
-+ * Arguments: tty pointer to associated tty instance data
-+ * Return Value: None
-+ */
-+static void hci_uart_tty_wakeup(struct tty_struct *tty)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+
-+ BT_DBG("");
-+
-+ if (!hu)
-+ return;
-+
-+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-+
-+ if (tty != hu->tty)
-+ return;
-+
-+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ hci_uart_tx_wakeup(hu);
-+}
-+
-+/* hci_uart_tty_room()
-+ *
-+ * Callback function from tty driver. Return the amount of
-+ * space left in the receiver's buffer to decide if remote
-+ * transmitter is to be throttled.
-+ *
-+ * Arguments: tty pointer to associated tty instance data
-+ * Return Value: number of bytes left in receive buffer
-+ */
-+static int hci_uart_tty_room (struct tty_struct *tty)
-+{
-+ return 65536;
-+}
-+
-+/* hci_uart_tty_receive()
-+ *
-+ * Called by tty low level driver when receive data is
-+ * available.
-+ *
-+ * Arguments: tty pointer to tty isntance data
-+ * data pointer to received data
-+ * flags pointer to flags for data
-+ * count count of received data in bytes
-+ *
-+ * Return Value: None
-+ */
-+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+
-+ if (!hu || tty != hu->tty)
-+ return;
-+
-+ if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ return;
-+
-+ spin_lock(&hu->rx_lock);
-+ hu->proto->recv(hu, (void *) data, count);
-+ hu->hdev.stat.byte_rx += count;
-+ spin_unlock(&hu->rx_lock);
-+
-+ if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
-+ tty->driver.unthrottle(tty);
-+}
-+
-+static int hci_uart_register_dev(struct hci_uart *hu)
-+{
-+ struct hci_dev *hdev;
-+
-+ BT_DBG("");
-+
-+ /* Initialize and register HCI device */
-+ hdev = &hu->hdev;
-+
-+ hdev->type = HCI_UART;
-+ hdev->driver_data = hu;
-+
-+ hdev->open = hci_uart_open;
-+ hdev->close = hci_uart_close;
-+ hdev->flush = hci_uart_flush;
-+ hdev->send = hci_uart_send_frame;
-+ hdev->destruct = hci_uart_destruct;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ BT_ERR("Can't register HCI device %s", hdev->name);
-+ return -ENODEV;
-+ }
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int hci_uart_set_proto(struct hci_uart *hu, int id)
-+{
-+ struct hci_uart_proto *p;
-+ int err;
-+
-+ p = hci_uart_get_proto(id);
-+ if (!p)
-+ return -EPROTONOSUPPORT;
-+
-+ err = p->open(hu);
-+ if (err)
-+ return err;
-+
-+ hu->proto = p;
-+
-+ err = hci_uart_register_dev(hu);
-+ if (err) {
-+ p->close(hu);
-+ return err;
-+ }
-+ return 0;
-+}
-+
-+/* hci_uart_tty_ioctl()
-+ *
-+ * Process IOCTL system call for the tty device.
-+ *
-+ * Arguments:
-+ *
-+ * tty pointer to tty instance data
-+ * file pointer to open file object for device
-+ * cmd IOCTL command code
-+ * arg argument for IOCTL call (cmd dependent)
-+ *
-+ * Return Value: Command dependent
-+ */
-+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ /* Verify the status of the device */
-+ if (!hu)
-+ return -EBADF;
-+
-+ switch (cmd) {
-+ case HCIUARTSETPROTO:
-+ if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-+ err = hci_uart_set_proto(hu, arg);
-+ if (err) {
-+ clear_bit(HCI_UART_PROTO_SET, &hu->flags);
-+ return err;
-+ }
-+ tty->low_latency = 1;
-+ } else
-+ return -EBUSY;
-+
-+ case HCIUARTGETPROTO:
-+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ return hu->proto->id;
-+ return -EUNATCH;
-+
-+ default:
-+ err = n_tty_ioctl(tty, file, cmd, arg);
-+ break;
-+ };
-+
-+ return err;
-+}
-+
-+/*
-+ * We don't provide read/write/poll interface for user space.
-+ */
-+static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
-+{
-+ return 0;
-+}
-+static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
-+{
-+ return 0;
-+}
-+static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
-+{
-+ return 0;
-+}
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+int h4_init(void);
-+int h4_deinit(void);
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+int bcsp_init(void);
-+int bcsp_deinit(void);
-+#endif
-+
-+int __init hci_uart_init(void)
-+{
-+ static struct tty_ldisc hci_uart_ldisc;
-+ int err;
-+
-+ BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ VERSION);
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+
-+ /* Register the tty discipline */
-+
-+ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
-+ hci_uart_ldisc.magic = TTY_LDISC_MAGIC;
-+ hci_uart_ldisc.name = "n_hci";
-+ hci_uart_ldisc.open = hci_uart_tty_open;
-+ hci_uart_ldisc.close = hci_uart_tty_close;
-+ hci_uart_ldisc.read = hci_uart_tty_read;
-+ hci_uart_ldisc.write = hci_uart_tty_write;
-+ hci_uart_ldisc.ioctl = hci_uart_tty_ioctl;
-+ hci_uart_ldisc.poll = hci_uart_tty_poll;
-+ hci_uart_ldisc.receive_room= hci_uart_tty_room;
-+ hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
-+ hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
-+
-+ if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
-+ BT_ERR("Can't register HCI line discipline (%d)", err);
-+ return err;
-+ }
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+ h4_init();
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+ bcsp_init();
-+#endif
-+
-+ return 0;
-+}
-+
-+void hci_uart_cleanup(void)
-+{
-+ int err;
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+ h4_deinit();
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+ bcsp_deinit();
-+#endif
-+
-+ /* Release tty registration of line discipline */
-+ if ((err = tty_register_ldisc(N_HCI, NULL)))
-+ BT_ERR("Can't unregister HCI line discipline (%d)", err);
-+}
-+
-+module_init(hci_uart_init);
-+module_exit(hci_uart_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.c linux-2.4.18-mh15/drivers/bluetooth/hci_uart.c
---- linux-2.4.18/drivers/bluetooth/hci_uart.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_uart.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,580 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * BlueZ HCI UART driver.
-- *
-- * $Id$
-- */
--#define VERSION "1.0"
--
--#include <linux/config.h>
--#include <linux/module.h>
--
--#include <linux/version.h>
--#include <linux/config.h>
--#include <linux/kernel.h>
--#include <linux/init.h>
--#include <linux/sched.h>
--#include <linux/types.h>
--#include <linux/fcntl.h>
--#include <linux/interrupt.h>
--#include <linux/ptrace.h>
--#include <linux/poll.h>
--
--#include <linux/slab.h>
--#include <linux/tty.h>
--#include <linux/errno.h>
--#include <linux/string.h>
--#include <linux/signal.h>
--#include <linux/ioctl.h>
--#include <linux/skbuff.h>
--
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_uart.h>
--
--#ifndef HCI_UART_DEBUG
--#undef DBG
--#define DBG( A... )
--#undef DMP
--#define DMP( A... )
--#endif
--
--/* ------- Interface to HCI layer ------ */
--/* Initialize device */
--int n_hci_open(struct hci_dev *hdev)
--{
-- DBG("%s %p", hdev->name, hdev);
--
-- /* Nothing to do for UART driver */
--
-- hdev->flags |= HCI_RUNNING;
--
-- return 0;
--}
--
--/* Reset device */
--int n_hci_flush(struct hci_dev *hdev)
--{
-- struct n_hci *n_hci = (struct n_hci *) hdev->driver_data;
-- struct tty_struct *tty = n_hci->tty;
--
-- DBG("hdev %p tty %p", hdev, tty);
--
-- /* Drop TX queue */
-- skb_queue_purge(&n_hci->txq);
--
-- /* Flush any pending characters in the driver and discipline. */
-- if (tty->ldisc.flush_buffer)
-- tty->ldisc.flush_buffer(tty);
--
-- if (tty->driver.flush_buffer)
-- tty->driver.flush_buffer(tty);
--
-- return 0;
--}
--
--/* Close device */
--int n_hci_close(struct hci_dev *hdev)
--{
-- DBG("hdev %p", hdev);
--
-- hdev->flags &= ~HCI_RUNNING;
--
-- n_hci_flush(hdev);
--
-- return 0;
--}
--
--int n_hci_tx_wakeup(struct n_hci *n_hci)
--{
-- register struct tty_struct *tty = n_hci->tty;
--
-- if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
-- set_bit(TRANS_WAKEUP, &n_hci->tx_state);
-- return 0;
-- }
--
-- DBG("");
-- do {
-- register struct sk_buff *skb;
-- register int len;
--
-- clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
--
-- if (!(skb = skb_dequeue(&n_hci->txq)))
-- break;
--
-- DMP(skb->data, skb->len);
--
-- /* Send frame to TTY driver */
-- tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-- len = tty->driver.write(tty, 0, skb->data, skb->len);
--
-- n_hci->hdev.stat.byte_tx += len;
--
-- DBG("sent %d", len);
--
-- if (len == skb->len) {
-- /* Full frame was sent */
-- kfree_skb(skb);
-- } else {
-- /* Subtract sent part and requeue */
-- skb_pull(skb, len);
-- skb_queue_head(&n_hci->txq, skb);
-- }
-- } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
-- clear_bit(TRANS_SENDING, &n_hci->tx_state);
--
-- return 0;
--}
--
--/* Send frames from HCI layer */
--int n_hci_send_frame(struct sk_buff *skb)
--{
-- struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-- struct tty_struct *tty;
-- struct n_hci *n_hci;
--
-- if (!hdev) {
-- ERR("Frame for uknown device (hdev=NULL)");
-- return -ENODEV;
-- }
--
-- if (!(hdev->flags & HCI_RUNNING))
-- return -EBUSY;
--
-- n_hci = (struct n_hci *) hdev->driver_data;
-- tty = n_hci2tty(n_hci);
--
-- DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
-- switch (skb->pkt_type) {
-- case HCI_COMMAND_PKT:
-- hdev->stat.cmd_tx++;
-- break;
--
-- case HCI_ACLDATA_PKT:
-- hdev->stat.acl_tx++;
-- break;
--
-- case HCI_SCODATA_PKT:
-- hdev->stat.cmd_tx++;
-- break;
-- };
--
-- /* Prepend skb with frame type and queue */
-- memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-- skb_queue_tail(&n_hci->txq, skb);
--
-- n_hci_tx_wakeup(n_hci);
--
-- return 0;
--}
--
--/* ------ LDISC part ------ */
--
--/* n_hci_tty_open
-- *
-- * Called when line discipline changed to N_HCI.
-- *
-- * Arguments:
-- * tty pointer to tty info structure
-- * Return Value:
-- * 0 if success, otherwise error code
-- */
--static int n_hci_tty_open(struct tty_struct *tty)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
-- struct hci_dev *hdev;
--
-- DBG("tty %p", tty);
--
-- if (n_hci)
-- return -EEXIST;
--
-- if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
-- ERR("Can't allocate controll structure");
-- return -ENFILE;
-- }
-- memset(n_hci, 0, sizeof(struct n_hci));
--
-- /* Initialize and register HCI device */
-- hdev = &n_hci->hdev;
--
-- hdev->type = HCI_UART;
-- hdev->driver_data = n_hci;
--
-- hdev->open = n_hci_open;
-- hdev->close = n_hci_close;
-- hdev->flush = n_hci_flush;
-- hdev->send = n_hci_send_frame;
--
-- if (hci_register_dev(hdev) < 0) {
-- ERR("Can't register HCI device %s", hdev->name);
-- kfree(n_hci);
-- return -ENODEV;
-- }
--
-- tty->disc_data = n_hci;
-- n_hci->tty = tty;
--
-- spin_lock_init(&n_hci->rx_lock);
-- n_hci->rx_state = WAIT_PACKET_TYPE;
--
-- skb_queue_head_init(&n_hci->txq);
--
-- MOD_INC_USE_COUNT;
--
-- /* Flush any pending characters in the driver and discipline. */
-- if (tty->ldisc.flush_buffer)
-- tty->ldisc.flush_buffer(tty);
--
-- if (tty->driver.flush_buffer)
-- tty->driver.flush_buffer(tty);
--
-- return 0;
--}
--
--/* n_hci_tty_close()
-- *
-- * Called when the line discipline is changed to something
-- * else, the tty is closed, or the tty detects a hangup.
-- */
--static void n_hci_tty_close(struct tty_struct *tty)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
-- struct hci_dev *hdev = &n_hci->hdev;
--
-- DBG("tty %p hdev %p", tty, hdev);
--
-- if (n_hci != NULL) {
-- n_hci_close(hdev);
--
-- if (hci_unregister_dev(hdev) < 0) {
-- ERR("Can't unregister HCI device %s",hdev->name);
-- }
--
-- hdev->driver_data = NULL;
-- tty->disc_data = NULL;
-- kfree(n_hci);
--
-- MOD_DEC_USE_COUNT;
-- }
--}
--
--/* n_hci_tty_wakeup()
-- *
-- * Callback for transmit wakeup. Called when low level
-- * device driver can accept more send data.
-- *
-- * Arguments: tty pointer to associated tty instance data
-- * Return Value: None
-- */
--static void n_hci_tty_wakeup( struct tty_struct *tty )
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
--
-- DBG("");
--
-- if (!n_hci)
-- return;
--
-- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
--
-- if (tty != n_hci->tty)
-- return;
--
-- n_hci_tx_wakeup(n_hci);
--}
--
--/* n_hci_tty_room()
-- *
-- * Callback function from tty driver. Return the amount of
-- * space left in the receiver's buffer to decide if remote
-- * transmitter is to be throttled.
-- *
-- * Arguments: tty pointer to associated tty instance data
-- * Return Value: number of bytes left in receive buffer
-- */
--static int n_hci_tty_room (struct tty_struct *tty)
--{
-- return 65536;
--}
--
--static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
--{
-- register int room = skb_tailroom(n_hci->rx_skb);
--
-- DBG("len %d room %d", len, room);
-- if (!len) {
-- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
-- hci_recv_frame(n_hci->rx_skb);
-- } else if (len > room) {
-- ERR("Data length is to large");
-- kfree_skb(n_hci->rx_skb);
-- n_hci->hdev.stat.err_rx++;
-- } else {
-- n_hci->rx_state = WAIT_DATA;
-- n_hci->rx_count = len;
-- return len;
-- }
--
-- n_hci->rx_state = WAIT_PACKET_TYPE;
-- n_hci->rx_skb = NULL;
-- n_hci->rx_count = 0;
-- return 0;
--}
--
--static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
--{
-- register const char *ptr;
-- hci_event_hdr *eh;
-- hci_acl_hdr *ah;
-- hci_sco_hdr *sh;
-- register int len, type, dlen;
--
-- DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);
--
-- n_hci->hdev.stat.byte_rx += count;
--
-- ptr = data;
-- while (count) {
-- if (n_hci->rx_count) {
-- len = MIN(n_hci->rx_count, count);
-- memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
-- n_hci->rx_count -= len; count -= len; ptr += len;
--
-- if (n_hci->rx_count)
-- continue;
--
-- switch (n_hci->rx_state) {
-- case WAIT_DATA:
-- DBG("Complete data");
--
-- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
--
-- hci_recv_frame(n_hci->rx_skb);
--
-- n_hci->rx_state = WAIT_PACKET_TYPE;
-- n_hci->rx_skb = NULL;
-- continue;
--
-- case WAIT_EVENT_HDR:
-- eh = (hci_event_hdr *) n_hci->rx_skb->data;
--
-- DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
--
-- n_hci_check_data_len(n_hci, eh->plen);
-- continue;
--
-- case WAIT_ACL_HDR:
-- ah = (hci_acl_hdr *) n_hci->rx_skb->data;
-- dlen = __le16_to_cpu(ah->dlen);
--
-- DBG("ACL header: dlen %d", dlen);
--
-- n_hci_check_data_len(n_hci, dlen);
-- continue;
--
-- case WAIT_SCO_HDR:
-- sh = (hci_sco_hdr *) n_hci->rx_skb->data;
--
-- DBG("SCO header: dlen %d", sh->dlen);
--
-- n_hci_check_data_len(n_hci, sh->dlen);
-- continue;
-- };
-- }
--
-- /* WAIT_PACKET_TYPE */
-- switch (*ptr) {
-- case HCI_EVENT_PKT:
-- DBG("Event packet");
-- n_hci->rx_state = WAIT_EVENT_HDR;
-- n_hci->rx_count = HCI_EVENT_HDR_SIZE;
-- type = HCI_EVENT_PKT;
-- break;
--
-- case HCI_ACLDATA_PKT:
-- DBG("ACL packet");
-- n_hci->rx_state = WAIT_ACL_HDR;
-- n_hci->rx_count = HCI_ACL_HDR_SIZE;
-- type = HCI_ACLDATA_PKT;
-- break;
--
-- case HCI_SCODATA_PKT:
-- DBG("SCO packet");
-- n_hci->rx_state = WAIT_SCO_HDR;
-- n_hci->rx_count = HCI_SCO_HDR_SIZE;
-- type = HCI_SCODATA_PKT;
-- break;
--
-- default:
-- ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-- n_hci->hdev.stat.err_rx++;
-- ptr++; count--;
-- continue;
-- };
-- ptr++; count--;
--
-- /* Allocate packet */
-- if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-- ERR("Can't allocate mem for new packet");
--
-- n_hci->rx_state = WAIT_PACKET_TYPE;
-- n_hci->rx_count = 0;
-- return;
-- }
-- n_hci->rx_skb->dev = (void *) &n_hci->hdev;
-- n_hci->rx_skb->pkt_type = type;
-- }
--}
--
--/* n_hci_tty_receive()
-- *
-- * Called by tty low level driver when receive data is
-- * available.
-- *
-- * Arguments: tty pointer to tty isntance data
-- * data pointer to received data
-- * flags pointer to flags for data
-- * count count of received data in bytes
-- *
-- * Return Value: None
-- */
--static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
--
-- if (!n_hci || tty != n_hci->tty)
-- return;
--
-- spin_lock(&n_hci->rx_lock);
-- n_hci_rx(n_hci, data, flags, count);
-- spin_unlock(&n_hci->rx_lock);
--
-- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
-- tty->driver.unthrottle(tty);
--}
--
--/* n_hci_tty_ioctl()
-- *
-- * Process IOCTL system call for the tty device.
-- *
-- * Arguments:
-- *
-- * tty pointer to tty instance data
-- * file pointer to open file object for device
-- * cmd IOCTL command code
-- * arg argument for IOCTL call (cmd dependent)
-- *
-- * Return Value: Command dependent
-- */
--static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
-- unsigned int cmd, unsigned long arg)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
-- int error = 0;
--
-- DBG("");
--
-- /* Verify the status of the device */
-- if (!n_hci)
-- return -EBADF;
--
-- switch (cmd) {
-- default:
-- error = n_tty_ioctl(tty, file, cmd, arg);
-- break;
-- };
--
-- return error;
--}
--
--/*
-- * We don't provide read/write/poll interface for user space.
-- */
--static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
--{
-- return 0;
--}
--static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
--{
-- return 0;
--}
--static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
--{
-- return 0;
--}
--
--int __init n_hci_init(void)
--{
-- static struct tty_ldisc n_hci_ldisc;
-- int err;
--
-- INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
--
-- /* Register the tty discipline */
--
-- memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
-- n_hci_ldisc.magic = TTY_LDISC_MAGIC;
-- n_hci_ldisc.name = "n_hci";
-- n_hci_ldisc.open = n_hci_tty_open;
-- n_hci_ldisc.close = n_hci_tty_close;
-- n_hci_ldisc.read = n_hci_tty_read;
-- n_hci_ldisc.write = n_hci_tty_write;
-- n_hci_ldisc.ioctl = n_hci_tty_ioctl;
-- n_hci_ldisc.poll = n_hci_tty_poll;
-- n_hci_ldisc.receive_room= n_hci_tty_room;
-- n_hci_ldisc.receive_buf = n_hci_tty_receive;
-- n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
--
-- if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
-- ERR("Can't register HCI line discipline (%d)", err);
-- return err;
-- }
--
-- return 0;
--}
--
--void n_hci_cleanup(void)
--{
-- int err;
--
-- /* Release tty registration of line discipline */
-- if ((err = tty_register_ldisc(N_HCI, NULL)))
-- ERR("Can't unregister HCI line discipline (%d)", err);
--}
--
--module_init(n_hci_init);
--module_exit(n_hci_cleanup);
--
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
--MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.h linux-2.4.18-mh15/drivers/bluetooth/hci_uart.h
---- linux-2.4.18/drivers/bluetooth/hci_uart.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_uart.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,82 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef N_HCI
-+#define N_HCI 15
-+#endif
-+
-+/* Ioctls */
-+#define HCIUARTSETPROTO _IOW('U', 200, int)
-+#define HCIUARTGETPROTO _IOR('U', 201, int)
-+
-+/* UART protocols */
-+#define HCI_UART_MAX_PROTO 4
-+
-+#define HCI_UART_H4 0
-+#define HCI_UART_BCSP 1
-+#define HCI_UART_3WIRE 2
-+#define HCI_UART_H4DS 3
-+
-+#ifdef __KERNEL__
-+struct hci_uart;
-+
-+struct hci_uart_proto {
-+ unsigned int id;
-+ int (*open)(struct hci_uart *hu);
-+ int (*close)(struct hci_uart *hu);
-+ int (*flush)(struct hci_uart *hu);
-+ int (*recv)(struct hci_uart *hu, void *data, int len);
-+ int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
-+ struct sk_buff *(*dequeue)(struct hci_uart *hu);
-+};
-+
-+struct hci_uart {
-+ struct tty_struct *tty;
-+ struct hci_dev hdev;
-+ unsigned long flags;
-+
-+ struct hci_uart_proto *proto;
-+ void *priv;
-+
-+ struct sk_buff *tx_skb;
-+ unsigned long tx_state;
-+ spinlock_t rx_lock;
-+};
-+
-+/* HCI_UART flag bits */
-+#define HCI_UART_PROTO_SET 0
-+
-+/* TX states */
-+#define HCI_UART_SENDING 1
-+#define HCI_UART_TX_WAKEUP 2
-+
-+int hci_uart_register_proto(struct hci_uart_proto *p);
-+int hci_uart_unregister_proto(struct hci_uart_proto *p);
-+int hci_uart_tx_wakeup(struct hci_uart *hu);
-+
-+#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.c linux-2.4.18-mh15/drivers/bluetooth/hci_usb.c
---- linux-2.4.18/drivers/bluetooth/hci_usb.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_usb.c 2004-08-01 16:26:23.000000000 +0200
-@@ -1,9 +1,10 @@
- /*
-- BlueZ - Bluetooth protocol stack for Linux
-+ HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
- Copyright (C) 2000-2001 Qualcomm Incorporated
--
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-+ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
-+
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-@@ -23,598 +24,938 @@
- */
-
- /*
-- * BlueZ HCI USB driver.
- * Based on original USB Bluetooth driver for Linux kernel
- * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
- *
-- * $Id$
-+ * $Id$
- */
--#define VERSION "1.0"
-+#define VERSION "2.7"
-
- #include <linux/config.h>
- #include <linux/module.h>
-
- #include <linux/version.h>
--#include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/sched.h>
-+#include <linux/unistd.h>
- #include <linux/types.h>
--#include <linux/fcntl.h>
- #include <linux/interrupt.h>
--#include <linux/ptrace.h>
--#include <linux/poll.h>
-
- #include <linux/slab.h>
--#include <linux/tty.h>
- #include <linux/errno.h>
- #include <linux/string.h>
--#include <linux/signal.h>
--#include <linux/ioctl.h>
- #include <linux/skbuff.h>
-
- #include <linux/usb.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_usb.h>
-+
-+#include "hci_usb.h"
-
- #ifndef HCI_USB_DEBUG
--#undef DBG
--#define DBG( A... )
--#undef DMP
--#define DMP( A... )
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
- #endif
-
--static struct usb_device_id usb_bluetooth_ids [] = {
-+#ifndef CONFIG_BLUEZ_HCIUSB_ZERO_PACKET
-+#undef USB_ZERO_PACKET
-+#define USB_ZERO_PACKET 0
-+#endif
-+
-+static struct usb_driver hci_usb_driver;
-+
-+static struct usb_device_id bluetooth_ids[] = {
-+ /* Generic Bluetooth USB device */
- { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
-+
-+ /* AVM BlueFRITZ! USB v2.0 */
-+ { USB_DEVICE(0x057c, 0x3800) },
-+
-+ /* Bluetooth Ultraport Module from IBM */
-+ { USB_DEVICE(0x04bf, 0x030a) },
-+
-+ /* ALPS Modules with non-standard id */
-+ { USB_DEVICE(0x044e, 0x3001) },
-+ { USB_DEVICE(0x044e, 0x3002) },
-+
-+ /* Ericsson with non-standard id */
-+ { USB_DEVICE(0x0bdb, 0x1002) },
-+
- { } /* Terminating entry */
- };
-
--MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
-+MODULE_DEVICE_TABLE (usb, bluetooth_ids);
-
--static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb);
--static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
-+static struct usb_device_id blacklist_ids[] = {
-+ /* Broadcom BCM2033 without firmware */
-+ { USB_DEVICE(0x0a5c, 0x2033), driver_info: HCI_IGNORE },
-
--static void hci_usb_unlink_urbs(struct hci_usb *husb)
-+ /* Broadcom BCM2035 */
-+ { USB_DEVICE(0x0a5c, 0x200a), driver_info: HCI_RESET },
-+
-+ /* ISSC Bluetooth Adapter v3.1 */
-+ { USB_DEVICE(0x1131, 0x1001), driver_info: HCI_RESET },
-+
-+ /* Digianswer device */
-+ { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER },
-+
-+ /* RTX Telecom based adapter with buggy SCO support */
-+ { USB_DEVICE(0x0400, 0x0807), driver_info: HCI_BROKEN_ISOC },
-+
-+ { } /* Terminating entry */
-+};
-+
-+struct _urb *_urb_alloc(int isoc, int gfp)
- {
-- usb_unlink_urb(husb->read_urb);
-- usb_unlink_urb(husb->intr_urb);
-- usb_unlink_urb(husb->ctrl_urb);
-- usb_unlink_urb(husb->write_urb);
-+ struct _urb *_urb = kmalloc(sizeof(struct _urb) +
-+ sizeof(iso_packet_descriptor_t) * isoc, gfp);
-+ if (_urb) {
-+ memset(_urb, 0, sizeof(*_urb));
-+ spin_lock_init(&_urb->urb.lock);
-+ }
-+ return _urb;
-+}
-+
-+struct _urb *_urb_dequeue(struct _urb_queue *q)
-+{
-+ struct _urb *_urb = NULL;
-+ unsigned long flags;
-+ spin_lock_irqsave(&q->lock, flags);
-+ {
-+ struct list_head *head = &q->head;
-+ struct list_head *next = head->next;
-+ if (next != head) {
-+ _urb = list_entry(next, struct _urb, list);
-+ list_del(next); _urb->queue = NULL;
-+ }
-+ }
-+ spin_unlock_irqrestore(&q->lock, flags);
-+ return _urb;
- }
-
--static void hci_usb_free_bufs(struct hci_usb *husb)
-+static void hci_usb_rx_complete(struct urb *urb);
-+static void hci_usb_tx_complete(struct urb *urb);
-+
-+#define __pending_tx(husb, type) (&husb->pending_tx[type-1])
-+#define __pending_q(husb, type) (&husb->pending_q[type-1])
-+#define __completed_q(husb, type) (&husb->completed_q[type-1])
-+#define __transmit_q(husb, type) (&husb->transmit_q[type-1])
-+#define __reassembly(husb, type) (husb->reassembly[type-1])
-+
-+static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
- {
-- if (husb->read_urb) {
-- if (husb->read_urb->transfer_buffer)
-- kfree(husb->read_urb->transfer_buffer);
-- usb_free_urb(husb->read_urb);
-- }
-+ return _urb_dequeue(__completed_q(husb, type));
-+}
-
-- if (husb->intr_urb) {
-- if (husb->intr_urb->transfer_buffer)
-- kfree(husb->intr_urb->transfer_buffer);
-- usb_free_urb(husb->intr_urb);
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
-+{
-+ int offset = 0, i;
-+
-+ BT_DBG("len %d mtu %d", len, mtu);
-+
-+ for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
-+ urb->iso_frame_desc[i].offset = offset;
-+ urb->iso_frame_desc[i].length = mtu;
-+ BT_DBG("desc %d offset %d len %d", i, offset, mtu);
-+ }
-+ if (len && i < HCI_MAX_ISOC_FRAMES) {
-+ urb->iso_frame_desc[i].offset = offset;
-+ urb->iso_frame_desc[i].length = len;
-+ BT_DBG("desc %d offset %d len %d", i, offset, len);
-+ i++;
- }
-+ urb->number_of_packets = i;
-+}
-+#endif
-
-- if (husb->ctrl_urb)
-- usb_free_urb(husb->ctrl_urb);
-+static int hci_usb_intr_rx_submit(struct hci_usb *husb)
-+{
-+ struct _urb *_urb;
-+ struct urb *urb;
-+ int err, pipe, interval, size;
-+ void *buf;
-+
-+ BT_DBG("%s", husb->hdev.name);
-+
-+ size = husb->intr_in_ep->wMaxPacketSize;
-+
-+ buf = kmalloc(size, GFP_ATOMIC);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb) {
-+ kfree(buf);
-+ return -ENOMEM;
-+ }
-+ _urb->type = HCI_EVENT_PKT;
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+
-+ urb = &_urb->urb;
-+ pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress);
-+ interval = husb->intr_in_ep->bInterval;
-+ FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s intr rx submit failed urb %p err %d",
-+ husb->hdev.name, urb, err);
-+ _urb_unlink(_urb);
-+ _urb_free(_urb);
-+ kfree(buf);
-+ }
-+ return err;
-+}
-
-- if (husb->write_urb)
-- usb_free_urb(husb->write_urb);
-+static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
-+{
-+ struct _urb *_urb;
-+ struct urb *urb;
-+ int err, pipe, size = HCI_MAX_FRAME_SIZE;
-+ void *buf;
-+
-+ buf = kmalloc(size, GFP_ATOMIC);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb) {
-+ kfree(buf);
-+ return -ENOMEM;
-+ }
-+ _urb->type = HCI_ACLDATA_PKT;
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+
-+ urb = &_urb->urb;
-+ pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress);
-+ FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ BT_DBG("%s urb %p", husb->hdev.name, urb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk rx submit failed urb %p err %d",
-+ husb->hdev.name, urb, err);
-+ _urb_unlink(_urb);
-+ _urb_free(_urb);
-+ kfree(buf);
-+ }
-+ return err;
-+}
-
-- if (husb->intr_skb)
-- kfree_skb(husb->intr_skb);
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
-+{
-+ struct _urb *_urb;
-+ struct urb *urb;
-+ int err, mtu, size;
-+ void *buf;
-+
-+ mtu = husb->isoc_in_ep->wMaxPacketSize;
-+ size = mtu * HCI_MAX_ISOC_FRAMES;
-+
-+ buf = kmalloc(size, GFP_ATOMIC);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-+ if (!_urb) {
-+ kfree(buf);
-+ return -ENOMEM;
-+ }
-+ _urb->type = HCI_SCODATA_PKT;
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+
-+ urb = &_urb->urb;
-+
-+ urb->context = husb;
-+ urb->dev = husb->udev;
-+ urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress);
-+ urb->complete = hci_usb_rx_complete;
-+
-+ urb->transfer_buffer_length = size;
-+ urb->transfer_buffer = buf;
-+ urb->transfer_flags = USB_ISO_ASAP;
-+
-+ __fill_isoc_desc(urb, size, mtu);
-+
-+ BT_DBG("%s urb %p", husb->hdev.name, urb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s isoc rx submit failed urb %p err %d",
-+ husb->hdev.name, urb, err);
-+ _urb_unlink(_urb);
-+ _urb_free(_urb);
-+ kfree(buf);
-+ }
-+ return err;
- }
-+#endif
-
--/* ------- Interface to HCI layer ------ */
- /* Initialize device */
--int hci_usb_open(struct hci_dev *hdev)
-+static int hci_usb_open(struct hci_dev *hdev)
- {
- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-- int status;
-+ int i, err;
-+ unsigned long flags;
-+
-+ BT_DBG("%s", hdev->name);
-
-- DBG("%s", hdev->name);
-+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-
-- husb->read_urb->dev = husb->udev;
-- if ((status = usb_submit_urb(husb->read_urb)))
-- DBG("read submit failed. %d", status);
-+ MOD_INC_USE_COUNT;
-
-- husb->intr_urb->dev = husb->udev;
-- if ((status = usb_submit_urb(husb->intr_urb)))
-- DBG("interrupt submit failed. %d", status);
-+ write_lock_irqsave(&husb->completion_lock, flags);
-
-- hdev->flags |= HCI_RUNNING;
-+ err = hci_usb_intr_rx_submit(husb);
-+ if (!err) {
-+ for (i = 0; i < HCI_MAX_BULK_RX; i++)
-+ hci_usb_bulk_rx_submit(husb);
-+
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ if (husb->isoc_iface)
-+ for (i = 0; i < HCI_MAX_ISOC_RX; i++)
-+ hci_usb_isoc_rx_submit(husb);
-+#endif
-+ } else {
-+ clear_bit(HCI_RUNNING, &hdev->flags);
-+ MOD_DEC_USE_COUNT;
-+ }
-
-- return 0;
-+ write_unlock_irqrestore(&husb->completion_lock, flags);
-+ return err;
- }
-
- /* Reset device */
--int hci_usb_flush(struct hci_dev *hdev)
-+static int hci_usb_flush(struct hci_dev *hdev)
- {
- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ int i;
-
-- DBG("%s", hdev->name);
--
-- /* Drop TX queues */
-- skb_queue_purge(&husb->tx_ctrl_q);
-- skb_queue_purge(&husb->tx_write_q);
-+ BT_DBG("%s", hdev->name);
-
-+ for (i=0; i < 4; i++)
-+ skb_queue_purge(&husb->transmit_q[i]);
- return 0;
- }
-
--/* Close device */
--int hci_usb_close(struct hci_dev *hdev)
-+static void hci_usb_unlink_urbs(struct hci_usb *husb)
- {
-- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ int i;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s", husb->hdev.name);
-
-- hdev->flags &= ~HCI_RUNNING;
-- hci_usb_unlink_urbs(husb);
-+ for (i=0; i < 4; i++) {
-+ struct _urb *_urb;
-+ struct urb *urb;
-+
-+ /* Kill pending requests */
-+ while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
-+ urb = &_urb->urb;
-+ BT_DBG("%s unlinking _urb %p type %d urb %p",
-+ husb->hdev.name, _urb, _urb->type, urb);
-+ usb_unlink_urb(urb);
-+ _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+ }
-
-- hci_usb_flush(hdev);
-+ /* Release completed requests */
-+ while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
-+ urb = &_urb->urb;
-+ BT_DBG("%s freeing _urb %p type %d urb %p",
-+ husb->hdev.name, _urb, _urb->type, urb);
-+ if (urb->setup_packet)
-+ kfree(urb->setup_packet);
-+ if (urb->transfer_buffer)
-+ kfree(urb->transfer_buffer);
-+ _urb_free(_urb);
-+ }
-
-- return 0;
-+ /* Release reassembly buffers */
-+ if (husb->reassembly[i]) {
-+ kfree_skb(husb->reassembly[i]);
-+ husb->reassembly[i] = NULL;
-+ }
-+ }
- }
-
--void hci_usb_ctrl_wakeup(struct hci_usb *husb)
-+/* Close device */
-+static int hci_usb_close(struct hci_dev *hdev)
- {
-- struct sk_buff *skb;
-+ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ unsigned long flags;
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-
-- if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
-- return;
-+ BT_DBG("%s", hdev->name);
-
-- DBG("%s", husb->hdev.name);
-+ write_lock_irqsave(&husb->completion_lock, flags);
-+
-+ hci_usb_unlink_urbs(husb);
-+ hci_usb_flush(hdev);
-
-- if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
-- goto done;
-+ write_unlock_irqrestore(&husb->completion_lock, flags);
-
-- if (hci_usb_ctrl_msg(husb, skb)){
-- kfree_skb(skb);
-- goto done;
-- }
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-
-- DMP(skb->data, skb->len);
-+static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
-+{
-+ struct urb *urb = &_urb->urb;
-+ int err;
-
-- husb->hdev.stat.byte_tx += skb->len;
-- return;
-+ BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type);
-+
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s tx submit failed urb %p type %d err %d",
-+ husb->hdev.name, urb, _urb->type, err);
-+ _urb_unlink(_urb);
-+ _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+ } else
-+ atomic_inc(__pending_tx(husb, _urb->type));
-
--done:
-- clear_bit(HCI_TX_CTRL, &husb->tx_state);
-- return;
-+ return err;
- }
-
--void hci_usb_write_wakeup(struct hci_usb *husb)
-+static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
- {
-- struct sk_buff *skb;
-+ struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+ devrequest *dr;
-+ struct urb *urb;
-+
-+ if (!_urb) {
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb)
-+ return -ENOMEM;
-+ _urb->type = skb->pkt_type;
-+
-+ dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
-+ if (!dr) {
-+ _urb_free(_urb);
-+ return -ENOMEM;
-+ }
-+ } else
-+ dr = (void *) _urb->urb.setup_packet;
-
-- if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
-- return;
-+ dr->requesttype = husb->ctrl_req;
-+ dr->request = 0;
-+ dr->index = 0;
-+ dr->value = 0;
-+ dr->length = __cpu_to_le16(skb->len);
-
-- DBG("%s", husb->hdev.name);
-+ urb = &_urb->urb;
-+ FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
-+ (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
-
-- if (!(skb = skb_dequeue(&husb->tx_write_q)))
-- goto done;
-+ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-+
-+ _urb->priv = skb;
-+ return __tx_submit(husb, _urb);
-+}
-
-- if (hci_usb_write_msg(husb, skb)) {
-- skb_queue_head(&husb->tx_write_q, skb);
-- goto done;
-+static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
-+{
-+ struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+ struct urb *urb;
-+ int pipe;
-+
-+ if (!_urb) {
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb)
-+ return -ENOMEM;
-+ _urb->type = skb->pkt_type;
- }
-
-- DMP(skb->data, skb->len);
-+ urb = &_urb->urb;
-+ pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress);
-+ FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
-+ hci_usb_tx_complete, husb);
-+ urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
-
-- husb->hdev.stat.byte_tx += skb->len;
-- return;
-+ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-
--done:
-- clear_bit(HCI_TX_WRITE, &husb->tx_state);
-- return;
-+ _urb->priv = skb;
-+ return __tx_submit(husb, _urb);
- }
-
--/* Send frames from HCI layer */
--int hci_usb_send_frame(struct sk_buff *skb)
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
- {
-- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-- struct hci_usb *husb;
--
-- if (!hdev) {
-- ERR("frame for uknown device (hdev=NULL)");
-- return -ENODEV;
-+ struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+ struct urb *urb;
-+
-+ if (!_urb) {
-+ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-+ if (!_urb)
-+ return -ENOMEM;
-+ _urb->type = skb->pkt_type;
- }
-
-- if (!(hdev->flags & HCI_RUNNING))
-- return 0;
-+ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-
-- husb = (struct hci_usb *) hdev->driver_data;
-+ urb = &_urb->urb;
-+
-+ urb->context = husb;
-+ urb->dev = husb->udev;
-+ urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress);
-+ urb->complete = hci_usb_tx_complete;
-+ urb->transfer_flags = USB_ISO_ASAP;
-
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+ urb->transfer_buffer = skb->data;
-+ urb->transfer_buffer_length = skb->len;
-+
-+ __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize);
-
-- switch (skb->pkt_type) {
-- case HCI_COMMAND_PKT:
-- skb_queue_tail(&husb->tx_ctrl_q, skb);
-- hci_usb_ctrl_wakeup(husb);
-- hdev->stat.cmd_tx++;
-- return 0;
--
-- case HCI_ACLDATA_PKT:
-- skb_queue_tail(&husb->tx_write_q, skb);
-- hci_usb_write_wakeup(husb);
-- hdev->stat.acl_tx++;
-- return 0;
--
-- case HCI_SCODATA_PKT:
-- return -EOPNOTSUPP;
-- };
--
-- return 0;
-+ _urb->priv = skb;
-+ return __tx_submit(husb, _urb);
- }
-+#endif
-
--/* ---------- USB ------------- */
--
--static void hci_usb_ctrl(struct urb *urb)
-+static void hci_usb_tx_process(struct hci_usb *husb)
- {
-- struct sk_buff *skb = (struct sk_buff *) urb->context;
-- struct hci_dev *hdev;
-- struct hci_usb *husb;
-+ struct sk_buff_head *q;
-+ struct sk_buff *skb;
-
-- if (!skb)
-- return;
-- hdev = (struct hci_dev *) skb->dev;
-- husb = (struct hci_usb *) hdev->driver_data;
-+ BT_DBG("%s", husb->hdev.name);
-
-- DBG("%s", hdev->name);
-+ do {
-+ clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
-
-- if (urb->status)
-- DBG("%s ctrl status: %d", hdev->name, urb->status);
-+ /* Process command queue */
-+ q = __transmit_q(husb, HCI_COMMAND_PKT);
-+ if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
-+ (skb = skb_dequeue(q))) {
-+ if (hci_usb_send_ctrl(husb, skb) < 0)
-+ skb_queue_head(q, skb);
-+ }
-
-- clear_bit(HCI_TX_CTRL, &husb->tx_state);
-- kfree_skb(skb);
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ /* Process SCO queue */
-+ q = __transmit_q(husb, HCI_SCODATA_PKT);
-+ if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
-+ (skb = skb_dequeue(q))) {
-+ if (hci_usb_send_isoc(husb, skb) < 0)
-+ skb_queue_head(q, skb);
-+ }
-+#endif
-+
-+ /* Process ACL queue */
-+ q = __transmit_q(husb, HCI_ACLDATA_PKT);
-+ while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
-+ (skb = skb_dequeue(q))) {
-+ if (hci_usb_send_bulk(husb, skb) < 0) {
-+ skb_queue_head(q, skb);
-+ break;
-+ }
-+ }
-+ } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
-+}
-
-- /* Wake up device */
-- hci_usb_ctrl_wakeup(husb);
-+static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
-+{
-+ /* Serialize TX queue processing to avoid data reordering */
-+ if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
-+ hci_usb_tx_process(husb);
-+ clear_bit(HCI_USB_TX_PROCESS, &husb->state);
-+ } else
-+ set_bit(HCI_USB_TX_WAKEUP, &husb->state);
- }
-
--static void hci_usb_bulk_write(struct urb *urb)
-+/* Send frames from HCI layer */
-+static int hci_usb_send_frame(struct sk_buff *skb)
- {
-- struct sk_buff *skb = (struct sk_buff *) urb->context;
-- struct hci_dev *hdev;
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- struct hci_usb *husb;
-
-- if (!skb)
-- return;
-- hdev = (struct hci_dev *) skb->dev;
-- husb = (struct hci_usb *) hdev->driver_data;
-+ if (!hdev) {
-+ BT_ERR("frame for uknown device (hdev=NULL)");
-+ return -ENODEV;
-+ }
-
-- DBG("%s", hdev->name);
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-
-- if (urb->status)
-- DBG("%s bulk write status: %d", hdev->name, urb->status);
-+ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-- clear_bit(HCI_TX_WRITE, &husb->tx_state);
-- kfree_skb(skb);
-+ husb = (struct hci_usb *) hdev->driver_data;
-
-- /* Wake up device */
-- hci_usb_write_wakeup(husb);
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+#endif
-
-- return;
--}
-+ default:
-+ kfree_skb(skb);
-+ return 0;
-+ }
-
--static void hci_usb_intr(struct urb *urb)
--{
-- struct hci_usb *husb = (struct hci_usb *) urb->context;
-- unsigned char *data = urb->transfer_buffer;
-- register int count = urb->actual_length;
-- register struct sk_buff *skb = husb->intr_skb;
-- hci_event_hdr *eh;
-- register int len;
-+ read_lock(&husb->completion_lock);
-
-- if (!husb)
-- return;
-+ skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
-+ hci_usb_tx_wakeup(husb);
-
-- DBG("%s count %d", husb->hdev.name, count);
-+ read_unlock(&husb->completion_lock);
-+ return 0;
-+}
-
-- if (urb->status || !count) {
-- DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
-- return;
-- }
-+static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
-+{
-+ BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count);
-
-- /* Do we really have to handle continuations here ? */
-- if (!skb) {
-- /* New frame */
-- if (count < HCI_EVENT_HDR_SIZE) {
-- DBG("%s bad frame len %d", husb->hdev.name, count);
-- return;
-- }
-+ husb->hdev.stat.byte_rx += count;
-
-- eh = (hci_event_hdr *) data;
-- len = eh->plen + HCI_EVENT_HDR_SIZE;
-+ while (count) {
-+ struct sk_buff *skb = __reassembly(husb, type);
-+ struct { int expect; } *scb;
-+ int len = 0;
-+
-+ if (!skb) {
-+ /* Start of the frame */
-+
-+ switch (type) {
-+ case HCI_EVENT_PKT:
-+ if (count >= HCI_EVENT_HDR_SIZE) {
-+ hci_event_hdr *h = data;
-+ len = HCI_EVENT_HDR_SIZE + h->plen;
-+ } else
-+ return -EILSEQ;
-+ break;
-
-- if (count > len) {
-- DBG("%s corrupted frame, len %d", husb->hdev.name, count);
-- return;
-- }
-+ case HCI_ACLDATA_PKT:
-+ if (count >= HCI_ACL_HDR_SIZE) {
-+ hci_acl_hdr *h = data;
-+ len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
-+ } else
-+ return -EILSEQ;
-+ break;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ case HCI_SCODATA_PKT:
-+ if (count >= HCI_SCO_HDR_SIZE) {
-+ hci_sco_hdr *h = data;
-+ len = HCI_SCO_HDR_SIZE + h->dlen;
-+ } else
-+ return -EILSEQ;
-+ break;
-+#endif
-+ }
-+ BT_DBG("new packet len %d", len);
-
-- /* Allocate skb */
-- if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
-- ERR("Can't allocate mem for new packet");
-- return;
-+ skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s no memory for the packet", husb->hdev.name);
-+ return -ENOMEM;
-+ }
-+ skb->dev = (void *) &husb->hdev;
-+ skb->pkt_type = type;
-+
-+ __reassembly(husb, type) = skb;
-+
-+ scb = (void *) skb->cb;
-+ scb->expect = len;
-+ } else {
-+ /* Continuation */
-+ scb = (void *) skb->cb;
-+ len = scb->expect;
- }
-- skb->dev = (void *) &husb->hdev;
-- skb->pkt_type = HCI_EVENT_PKT;
--
-- husb->intr_skb = skb;
-- husb->intr_count = len;
-- } else {
-- /* Continuation */
-- if (count > husb->intr_count) {
-- ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
-
-- kfree_skb(skb);
-- husb->intr_skb = NULL;
-- husb->intr_count = 0;
-- return;
-+ len = min(len, count);
-+
-+ memcpy(skb_put(skb, len), data, len);
-+
-+ scb->expect -= len;
-+ if (!scb->expect) {
-+ /* Complete frame */
-+ __reassembly(husb, type) = NULL;
-+ hci_recv_frame(skb);
- }
-- }
--
-- memcpy(skb_put(skb, count), data, count);
-- husb->intr_count -= count;
--
-- DMP(data, count);
--
-- if (!husb->intr_count) {
-- /* Got complete frame */
-
-- husb->hdev.stat.byte_rx += skb->len;
-- hci_recv_frame(skb);
--
-- husb->intr_skb = NULL;
-+ count -= len; data += len;
- }
-+ return 0;
- }
-
--static void hci_usb_bulk_read(struct urb *urb)
-+static void hci_usb_rx_complete(struct urb *urb)
- {
-- struct hci_usb *husb = (struct hci_usb *) urb->context;
-- unsigned char *data = urb->transfer_buffer;
-- int count = urb->actual_length, status;
-- struct sk_buff *skb;
-- hci_acl_hdr *ah;
-- register __u16 dlen;
--
-- if (!husb)
-- return;
-+ struct _urb *_urb = container_of(urb, struct _urb, urb);
-+ struct hci_usb *husb = (void *) urb->context;
-+ struct hci_dev *hdev = &husb->hdev;
-+ int err, count = urb->actual_length;
-
-- DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
-+ BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
-+ _urb->type, urb->status, count, urb->transfer_flags);
-
-- if (urb->status) {
-- /* Do not re-submit URB on critical errors */
-- switch (urb->status) {
-- case -ENOENT:
-- return;
-- default:
-- goto resubmit;
-- };
-- }
-- if (!count)
-- goto resubmit;
--
-- DMP(data, count);
-+ read_lock(&husb->completion_lock);
-
-- ah = (hci_acl_hdr *) data;
-- dlen = le16_to_cpu(ah->dlen);
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ goto unlock;
-
-- /* Verify frame len and completeness */
-- if ((count - HCI_ACL_HDR_SIZE) != dlen) {
-- ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
-+ if (urb->status || !count)
- goto resubmit;
-- }
-
-- /* Allocate packet */
-- if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
-- ERR("Can't allocate mem for new packet");
-- goto resubmit;
-+ if (_urb->type == HCI_SCODATA_PKT) {
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ int i;
-+ for (i=0; i < urb->number_of_packets; i++) {
-+ BT_DBG("desc %d status %d offset %d len %d", i,
-+ urb->iso_frame_desc[i].status,
-+ urb->iso_frame_desc[i].offset,
-+ urb->iso_frame_desc[i].actual_length);
-+
-+ if (!urb->iso_frame_desc[i].status)
-+ __recv_frame(husb, _urb->type,
-+ urb->transfer_buffer + urb->iso_frame_desc[i].offset,
-+ urb->iso_frame_desc[i].actual_length);
-+ }
-+#else
-+ ;
-+#endif
-+ } else {
-+ err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
-+ if (err < 0) {
-+ BT_ERR("%s corrupted packet: type %d count %d",
-+ husb->hdev.name, _urb->type, count);
-+ hdev->stat.err_rx++;
-+ }
- }
-
-- memcpy(skb_put(skb, count), data, count);
-- skb->dev = (void *) &husb->hdev;
-- skb->pkt_type = HCI_ACLDATA_PKT;
--
-- husb->hdev.stat.byte_rx += skb->len;
--
-- hci_recv_frame(skb);
--
- resubmit:
-- husb->read_urb->dev = husb->udev;
-- if ((status = usb_submit_urb(husb->read_urb)))
-- DBG("%s read URB submit failed %d", husb->hdev.name, status);
-+ if (_urb->type != HCI_EVENT_PKT) {
-+ urb->dev = husb->udev;
-+ err = usb_submit_urb(urb);
-+ BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
-+ _urb->type, err);
-+ }
-
-- DBG("%s read URB re-submited", husb->hdev.name);
-+unlock:
-+ read_unlock(&husb->completion_lock);
- }
-
--static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
-+static void hci_usb_tx_complete(struct urb *urb)
- {
-- struct urb *urb = husb->ctrl_urb;
-- devrequest *dr = &husb->dev_req;
-- int pipe, status;
-+ struct _urb *_urb = container_of(urb, struct _urb, urb);
-+ struct hci_usb *husb = (void *) urb->context;
-+ struct hci_dev *hdev = &husb->hdev;
-
-- DBG("%s len %d", husb->hdev.name, skb->len);
-+ BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
-+ urb->status, urb->transfer_flags);
-
-- pipe = usb_sndctrlpipe(husb->udev, 0);
-+ atomic_dec(__pending_tx(husb, _urb->type));
-
-- dr->requesttype = HCI_CTRL_REQ;
-- dr->request = 0;
-- dr->index = 0;
-- dr->value = 0;
-- dr->length = cpu_to_le16(skb->len);
--
-- FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
-- hci_usb_ctrl, skb);
-+ urb->transfer_buffer = NULL;
-+ kfree_skb((struct sk_buff *) _urb->priv);
-
-- if ((status = usb_submit_urb(urb))) {
-- DBG("%s control URB submit failed %d", husb->hdev.name, status);
-- return status;
-- }
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return;
-
-- return 0;
--}
-+ if (!urb->status)
-+ hdev->stat.byte_tx += urb->transfer_buffer_length;
-+ else
-+ hdev->stat.err_tx++;
-
--static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
--{
-- struct urb *urb = husb->write_urb;
-- int pipe, status;
-+ read_lock(&husb->completion_lock);
-
-- DBG("%s len %d", husb->hdev.name, skb->len);
-+ _urb_unlink(_urb);
-+ _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-
-- pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
-+ hci_usb_tx_wakeup(husb);
-+
-+ read_unlock(&husb->completion_lock);
-+}
-
-- FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
-- hci_usb_bulk_write, skb);
-- urb->transfer_flags |= USB_QUEUE_BULK;
-+static void hci_usb_destruct(struct hci_dev *hdev)
-+{
-+ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-
-- if ((status = usb_submit_urb(urb))) {
-- DBG("%s write URB submit failed %d", husb->hdev.name, status);
-- return status;
-- }
-+ BT_DBG("%s", hdev->name);
-
-- return 0;
-+ kfree(husb);
- }
-
--static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
- {
-- struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
-+ struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];
- struct usb_interface_descriptor *uif;
- struct usb_endpoint_descriptor *ep;
-+ struct usb_interface *iface, *isoc_iface;
- struct hci_usb *husb;
- struct hci_dev *hdev;
-- int i, size, pipe;
-- __u8 * buf;
-+ int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
-
-- DBG("udev %p ifnum %d", udev, ifnum);
-+ BT_DBG("udev %p ifnum %d", udev, ifnum);
-
-- /* Check device signature */
-- if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) ||
-- (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
-- (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
-- return NULL;
-+ iface = &udev->actconfig->interface[0];
-
-- MOD_INC_USE_COUNT;
--
-- uif = &udev->actconfig->interface[ifnum].altsetting[0];
-+ if (!id->driver_info) {
-+ const struct usb_device_id *match;
-+ match = usb_match_id(udev, iface, blacklist_ids);
-+ if (match)
-+ id = match;
-+ }
-
-- if (uif->bNumEndpoints != 3) {
-- DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
-- MOD_DEC_USE_COUNT;
-+ if (id->driver_info & HCI_IGNORE)
- return NULL;
-- }
-
-- bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
-+ /* Check number of endpoints */
-+ if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
-+ return NULL;
-
-+ memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
-+ memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
-+ memset(bulk_in_ep, 0, sizeof(bulk_in_ep));
-+ memset(isoc_in_ep, 0, sizeof(isoc_in_ep));
-+ memset(intr_in_ep, 0, sizeof(intr_in_ep));
-+
-+ size = 0;
-+ isoc_iface = NULL;
-+ isoc_alts = isoc_ifnum = 0;
-+
- /* Find endpoints that we need */
-- for ( i = 0; i < uif->bNumEndpoints; ++i) {
-- ep = &uif->endpoint[i];
-
-- switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-- case USB_ENDPOINT_XFER_BULK:
-- if (ep->bEndpointAddress & USB_DIR_IN)
-- bulk_in_ep = ep;
-- else
-- bulk_out_ep = ep;
-- break;
-+ ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
-+ for (i = 0; i < ifn; i++) {
-+ iface = &udev->actconfig->interface[i];
-+ for (a = 0; a < iface->num_altsetting; a++) {
-+ uif = &iface->altsetting[a];
-+ for (e = 0; e < uif->bNumEndpoints; e++) {
-+ ep = &uif->endpoint[e];
-+
-+ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-+ case USB_ENDPOINT_XFER_INT:
-+ if (ep->bEndpointAddress & USB_DIR_IN)
-+ intr_in_ep[i] = ep;
-+ break;
-+
-+ case USB_ENDPOINT_XFER_BULK:
-+ if (ep->bEndpointAddress & USB_DIR_IN)
-+ bulk_in_ep[i] = ep;
-+ else
-+ bulk_out_ep[i] = ep;
-+ break;
-+
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ case USB_ENDPOINT_XFER_ISOC:
-+ if (ep->wMaxPacketSize < size || a > 2)
-+ break;
-+ size = ep->wMaxPacketSize;
-+
-+ isoc_iface = iface;
-+ isoc_alts = a;
-+ isoc_ifnum = i;
-+
-+ if (ep->bEndpointAddress & USB_DIR_IN)
-+ isoc_in_ep[i] = ep;
-+ else
-+ isoc_out_ep[i] = ep;
-+ break;
-+#endif
-+ }
-+ }
-+ }
-+ }
-
-- case USB_ENDPOINT_XFER_INT:
-- intr_in_ep = ep;
-- break;
-- };
-+ if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
-+ BT_DBG("Bulk endpoints not found");
-+ goto done;
- }
-
-- if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
-- DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
-- MOD_DEC_USE_COUNT;
-- return NULL;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ if (id->driver_info & HCI_BROKEN_ISOC || !isoc_in_ep[1] || !isoc_out_ep[1]) {
-+ BT_DBG("Isoc endpoints not found");
-+ isoc_iface = NULL;
- }
-+#endif
-
- if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
-- ERR("Can't allocate: control structure");
-- MOD_DEC_USE_COUNT;
-- return NULL;
-+ BT_ERR("Can't allocate: control structure");
-+ goto done;
- }
-
- memset(husb, 0, sizeof(struct hci_usb));
-
- husb->udev = udev;
-- husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
--
-- if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: control URB");
-- goto probe_error;
-- }
--
-- if (!(husb->write_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: write URB");
-- goto probe_error;
-- }
--
-- if (!(husb->read_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: read URB");
-- goto probe_error;
-- }
--
-- ep = bulk_in_ep;
-- pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
-- size = HCI_MAX_FRAME_SIZE;
--
-- if (!(buf = kmalloc(size, GFP_KERNEL))) {
-- ERR("Can't allocate: read buffer");
-- goto probe_error;
-- }
--
-- FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
-- husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
--
-- ep = intr_in_ep;
-- pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
-- size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
--
-- if (!(husb->intr_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: interrupt URB");
-- goto probe_error;
-+ husb->bulk_out_ep = bulk_out_ep[0];
-+ husb->bulk_in_ep = bulk_in_ep[0];
-+ husb->intr_in_ep = intr_in_ep[0];
-+
-+ if (id->driver_info & HCI_DIGIANSWER)
-+ husb->ctrl_req = HCI_DIGI_REQ;
-+ else
-+ husb->ctrl_req = HCI_CTRL_REQ;
-+
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+ if (isoc_iface) {
-+ BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
-+ if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
-+ BT_ERR("Can't set isoc interface settings");
-+ isoc_iface = NULL;
-+ }
-+ usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
-+ husb->isoc_iface = isoc_iface;
-+ husb->isoc_in_ep = isoc_in_ep[isoc_ifnum];
-+ husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
- }
-+#endif
-+
-+ husb->completion_lock = RW_LOCK_UNLOCKED;
-
-- if (!(buf = kmalloc(size, GFP_KERNEL))) {
-- ERR("Can't allocate: interrupt buffer");
-- goto probe_error;
-+ for (i = 0; i < 4; i++) {
-+ skb_queue_head_init(&husb->transmit_q[i]);
-+ _urb_queue_init(&husb->pending_q[i]);
-+ _urb_queue_init(&husb->completed_q[i]);
- }
-
-- FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
--
-- skb_queue_head_init(&husb->tx_ctrl_q);
-- skb_queue_head_init(&husb->tx_write_q);
--
- /* Initialize and register HCI device */
- hdev = &husb->hdev;
-
-- hdev->type = HCI_USB;
-+ hdev->type = HCI_USB;
- hdev->driver_data = husb;
-
- hdev->open = hci_usb_open;
- hdev->close = hci_usb_close;
- hdev->flush = hci_usb_flush;
-- hdev->send = hci_usb_send_frame;
-+ hdev->send = hci_usb_send_frame;
-+ hdev->destruct = hci_usb_destruct;
-+
-+ if (id->driver_info & HCI_RESET)
-+ set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
-
- if (hci_register_dev(hdev) < 0) {
-- ERR("Can't register HCI device %s", hdev->name);
-+ BT_ERR("Can't register HCI device");
- goto probe_error;
- }
-
- return husb;
-
- probe_error:
-- hci_usb_free_bufs(husb);
- kfree(husb);
-- MOD_DEC_USE_COUNT;
-+
-+done:
- return NULL;
- }
-
-@@ -626,38 +967,34 @@
- if (!husb)
- return;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s", hdev->name);
-
- hci_usb_close(hdev);
-
-- if (hci_unregister_dev(hdev) < 0) {
-- ERR("Can't unregister HCI device %s", hdev->name);
-- }
-+ if (husb->isoc_iface)
-+ usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
-
-- hci_usb_free_bufs(husb);
-- kfree(husb);
--
-- MOD_DEC_USE_COUNT;
-+ if (hci_unregister_dev(hdev) < 0)
-+ BT_ERR("Can't unregister HCI device %s", hdev->name);
- }
-
--static struct usb_driver hci_usb_driver =
--{
-+static struct usb_driver hci_usb_driver = {
- name: "hci_usb",
- probe: hci_usb_probe,
- disconnect: hci_usb_disconnect,
-- id_table: usb_bluetooth_ids,
-+ id_table: bluetooth_ids,
- };
-
- int hci_usb_init(void)
- {
- int err;
-
-- INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
- if ((err = usb_register(&hci_usb_driver)) < 0)
-- ERR("Failed to register HCI USB driver");
-+ BT_ERR("Failed to register HCI USB driver");
-
- return err;
- }
-@@ -670,6 +1007,6 @@
- module_init(hci_usb_init);
- module_exit(hci_usb_cleanup);
-
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
- MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION);
- MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.h linux-2.4.18-mh15/drivers/bluetooth/hci_usb.h
---- linux-2.4.18/drivers/bluetooth/hci_usb.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_usb.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,147 @@
-+/*
-+ HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifdef __KERNEL__
-+
-+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-+#define HCI_DEV_CLASS 0xe0 /* Wireless class */
-+#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */
-+#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */
-+
-+#define HCI_CTRL_REQ 0x20
-+#define HCI_DIGI_REQ 0x40
-+
-+#define HCI_IGNORE 0x01
-+#define HCI_RESET 0x02
-+#define HCI_DIGIANSWER 0x04
-+#define HCI_BROKEN_ISOC 0x08
-+
-+#define HCI_MAX_IFACE_NUM 3
-+
-+#define HCI_MAX_BULK_TX 4
-+#define HCI_MAX_BULK_RX 1
-+
-+#define HCI_MAX_ISOC_RX 2
-+#define HCI_MAX_ISOC_TX 2
-+
-+#define HCI_MAX_ISOC_FRAMES 10
-+
-+struct _urb_queue {
-+ struct list_head head;
-+ spinlock_t lock;
-+};
-+
-+struct _urb {
-+ struct list_head list;
-+ struct _urb_queue *queue;
-+ int type;
-+ void *priv;
-+ struct urb urb;
-+};
-+
-+struct _urb *_urb_alloc(int isoc, int gfp);
-+
-+static inline void _urb_free(struct _urb *_urb)
-+{
-+ kfree(_urb);
-+}
-+
-+static inline void _urb_queue_init(struct _urb_queue *q)
-+{
-+ INIT_LIST_HEAD(&q->head);
-+ spin_lock_init(&q->lock);
-+}
-+
-+static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
-+{
-+ unsigned long flags;
-+ spin_lock_irqsave(&q->lock, flags);
-+ list_add(&_urb->list, &q->head); _urb->queue = q;
-+ spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
-+{
-+ unsigned long flags;
-+ spin_lock_irqsave(&q->lock, flags);
-+ list_add_tail(&_urb->list, &q->head); _urb->queue = q;
-+ spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+static inline void _urb_unlink(struct _urb *_urb)
-+{
-+ struct _urb_queue *q = _urb->queue;
-+ unsigned long flags;
-+ if (q) {
-+ spin_lock_irqsave(&q->lock, flags);
-+ list_del(&_urb->list); _urb->queue = NULL;
-+ spin_unlock_irqrestore(&q->lock, flags);
-+ }
-+}
-+
-+struct _urb *_urb_dequeue(struct _urb_queue *q);
-+
-+#ifndef container_of
-+#define container_of(ptr, type, member) ({ \
-+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-+ (type *)( (char *)__mptr - offsetof(type,member) );})
-+#endif
-+
-+struct hci_usb {
-+ struct hci_dev hdev;
-+
-+ unsigned long state;
-+
-+ struct usb_device *udev;
-+
-+ struct usb_endpoint_descriptor *bulk_in_ep;
-+ struct usb_endpoint_descriptor *bulk_out_ep;
-+ struct usb_endpoint_descriptor *intr_in_ep;
-+
-+ struct usb_interface *isoc_iface;
-+ struct usb_endpoint_descriptor *isoc_out_ep;
-+ struct usb_endpoint_descriptor *isoc_in_ep;
-+
-+ __u8 ctrl_req;
-+
-+ struct sk_buff_head transmit_q[4];
-+ struct sk_buff *reassembly[4]; // Reassembly buffers
-+
-+ rwlock_t completion_lock;
-+
-+ atomic_t pending_tx[4]; // Number of pending requests
-+ struct _urb_queue pending_q[4]; // Pending requests
-+ struct _urb_queue completed_q[4]; // Completed requests
-+};
-+
-+/* States */
-+#define HCI_USB_TX_PROCESS 1
-+#define HCI_USB_TX_WAKEUP 2
-+
-+#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.c linux-2.4.18-mh15/drivers/bluetooth/hci_vhci.c
---- linux-2.4.18/drivers/bluetooth/hci_vhci.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_vhci.c 2004-08-01 16:26:23.000000000 +0200
-@@ -25,9 +25,9 @@
- /*
- * BlueZ HCI virtual device driver.
- *
-- * $Id$
-+ * $Id$
- */
--#define VERSION "1.0"
-+#define VERSION "1.1"
-
- #include <linux/config.h>
- #include <linux/module.h>
-@@ -49,43 +49,56 @@
- #include <asm/uaccess.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_vhci.h>
-+#include "hci_vhci.h"
-
- /* HCI device part */
-
--int hci_vhci_open(struct hci_dev *hdev)
-+static int hci_vhci_open(struct hci_dev *hdev)
- {
-- hdev->flags |= HCI_RUNNING;
-+ set_bit(HCI_RUNNING, &hdev->flags);
- return 0;
- }
-
--int hci_vhci_flush(struct hci_dev *hdev)
-+static int hci_vhci_flush(struct hci_dev *hdev)
- {
- struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
- skb_queue_purge(&hci_vhci->readq);
- return 0;
- }
-
--int hci_vhci_close(struct hci_dev *hdev)
-+static int hci_vhci_close(struct hci_dev *hdev)
- {
-- hdev->flags &= ~HCI_RUNNING;
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
- hci_vhci_flush(hdev);
- return 0;
- }
-
--int hci_vhci_send_frame(struct sk_buff *skb)
-+static void hci_vhci_destruct(struct hci_dev *hdev)
-+{
-+ struct hci_vhci_struct *vhci;
-+
-+ if (!hdev) return;
-+
-+ vhci = (struct hci_vhci_struct *) hdev->driver_data;
-+ kfree(vhci);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static int hci_vhci_send_frame(struct sk_buff *skb)
- {
- struct hci_dev* hdev = (struct hci_dev *) skb->dev;
- struct hci_vhci_struct *hci_vhci;
-
- if (!hdev) {
-- ERR("Frame for uknown device (hdev=NULL)");
-+ BT_ERR("Frame for uknown device (hdev=NULL)");
- return -ENODEV;
- }
-
-- if (!(hdev->flags & HCI_RUNNING))
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
- return -EBUSY;
-
- hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
-@@ -188,7 +201,7 @@
-
- add_wait_queue(&hci_vhci->read_wait, &wait);
- while (count) {
-- current->state = TASK_INTERRUPTIBLE;
-+ set_current_state(TASK_INTERRUPTIBLE);
-
- /* Read frames from device queue */
- if (!(skb = skb_dequeue(&hci_vhci->readq))) {
-@@ -214,8 +227,7 @@
- kfree_skb(skb);
- break;
- }
--
-- current->state = TASK_RUNNING;
-+ set_current_state(TASK_RUNNING);
- remove_wait_queue(&hci_vhci->read_wait, &wait);
-
- return ret;
-@@ -270,11 +282,13 @@
- hdev->close = hci_vhci_close;
- hdev->flush = hci_vhci_flush;
- hdev->send = hci_vhci_send_frame;
-+ hdev->destruct = hci_vhci_destruct;
-
- if (hci_register_dev(hdev) < 0) {
- kfree(hci_vhci);
- return -EBUSY;
- }
-+ MOD_INC_USE_COUNT;
-
- file->private_data = hci_vhci;
- return 0;
-@@ -285,12 +299,10 @@
- struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-
- if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
-- ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
-+ BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
- }
-
-- kfree(hci_vhci);
- file->private_data = NULL;
--
- return 0;
- }
-
-@@ -315,12 +327,12 @@
-
- int __init hci_vhci_init(void)
- {
-- INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
- if (misc_register(&hci_vhci_miscdev)) {
-- ERR("Can't register misc device %d\n", VHCI_MINOR);
-+ BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
- return -EIO;
- }
-
-@@ -337,4 +349,4 @@
-
- MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
- MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
--MODULE_LICENSE("GPL");
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.h linux-2.4.18-mh15/drivers/bluetooth/hci_vhci.h
---- linux-2.4.18/drivers/bluetooth/hci_vhci.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/hci_vhci.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,50 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __HCI_VHCI_H
-+#define __HCI_VHCI_H
-+
-+#ifdef __KERNEL__
-+
-+struct hci_vhci_struct {
-+ struct hci_dev hdev;
-+ __u32 flags;
-+ wait_queue_head_t read_wait;
-+ struct sk_buff_head readq;
-+ struct fasync_struct *fasync;
-+};
-+
-+/* VHCI device flags */
-+#define VHCI_FASYNC 0x0010
-+
-+#endif /* __KERNEL__ */
-+
-+#define VHCI_DEV "/dev/vhci"
-+#define VHCI_MINOR 250
-+
-+#endif /* __HCI_VHCI_H */
-diff -urN linux-2.4.18/drivers/bluetooth/Makefile linux-2.4.18-mh15/drivers/bluetooth/Makefile
---- linux-2.4.18/drivers/bluetooth/Makefile 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/bluetooth/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -1,11 +1,27 @@
- #
--# Makefile for Bluetooth HCI device drivers.
-+# Makefile for the Linux Bluetooth HCI device drivers
- #
-
- O_TARGET := bluetooth.o
-
-+list-multi := hci_uart.o
-+
- obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o
--obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
- obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o
-
-+obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
-+uart-y := hci_ldisc.o
-+uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o
-+uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o
-+
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o
-+
-+obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o
-+
- include $(TOPDIR)/Rules.make
-+
-+hci_uart.o: $(uart-y)
-+ $(LD) -r -o $@ $(uart-y)
-diff -urN linux-2.4.18/drivers/bluetooth/Makefile.lib linux-2.4.18-mh15/drivers/bluetooth/Makefile.lib
---- linux-2.4.18/drivers/bluetooth/Makefile.lib 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/bluetooth/Makefile.lib 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,2 @@
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
-+obj-$(CONFIG_BLUEZ_HCIBT3C) += firmware_class.o
-diff -urN linux-2.4.18/drivers/char/pcmcia/serial_cs.c linux-2.4.18-mh15/drivers/char/pcmcia/serial_cs.c
---- linux-2.4.18/drivers/char/pcmcia/serial_cs.c 2001-12-21 18:41:54.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/char/pcmcia/serial_cs.c 2004-08-01 16:26:23.000000000 +0200
-@@ -2,7 +2,7 @@
-
- A driver for PCMCIA serial devices
-
-- serial_cs.c 1.128 2001/10/18 12:18:35
-+ serial_cs.c 1.138 2002/10/25 06:24:52
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
-@@ -69,14 +69,14 @@
- static int irq_list[4] = { -1 };
- MODULE_PARM(irq_list, "1-4i");
-
--/* Enable the speaker? */
--INT_MODULE_PARM(do_sound, 1);
-+INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */
-+INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */
-
- #ifdef PCMCIA_DEBUG
- INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
- #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
- static char *version =
--"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
-+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
- #else
- #define DEBUG(n, args...)
- #endif
-@@ -95,6 +95,7 @@
- { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
-+ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
-@@ -148,7 +149,7 @@
- client_reg_t client_reg;
- dev_link_t *link;
- int i, ret;
--
-+
- DEBUG(0, "serial_attach()\n");
-
- /* Create new serial device */
-@@ -160,7 +161,7 @@
- link->release.function = &serial_release;
- link->release.data = (u_long)link;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-- link->io.NumPorts1 = 8;
-+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
-@@ -169,13 +170,12 @@
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
- link->conf.Attributes = CONF_ENABLE_IRQ;
-- link->conf.Vcc = 50;
- if (do_sound) {
- link->conf.Attributes |= CONF_ENABLE_SPKR;
- link->conf.Status = CCSR_AUDIO_ENA;
- }
- link->conf.IntType = INT_MEMORY_AND_IO;
--
-+
- /* Register with Card Services */
- link->next = dev_list;
- dev_list = link;
-@@ -194,7 +194,7 @@
- serial_detach(link);
- return NULL;
- }
--
-+
- return link;
- } /* serial_attach */
-
-@@ -214,7 +214,7 @@
- int ret;
-
- DEBUG(0, "serial_detach(0x%p)\n", link);
--
-+
- /* Locate device structure */
- for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
- if (*linkp == link) break;
-@@ -224,17 +224,17 @@
- del_timer(&link->release);
- if (link->state & DEV_CONFIG)
- serial_release((u_long)link);
--
-+
- if (link->handle) {
- ret = CardServices(DeregisterClient, link->handle);
- if (ret != CS_SUCCESS)
- cs_error(link->handle, DeregisterClient, ret);
- }
--
-+
- /* Unlink device structure, free bits */
- *linkp = link->next;
- kfree(info);
--
-+
- } /* serial_detach */
-
- /*====================================================================*/
-@@ -243,18 +243,20 @@
- {
- struct serial_struct serial;
- int line;
--
-+
- memset(&serial, 0, sizeof(serial));
- serial.port = port;
- serial.irq = irq;
- serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
-+ if (buggy_uart)
-+ serial.flags |= ASYNC_BUGGY_UART;
- line = register_serial(&serial);
- if (line < 0) {
- printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
- " irq %d failed\n", (u_long)serial.port, serial.irq);
- return -1;
- }
--
-+
- info->line[info->ndev] = line;
- sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
- info->node[info->ndev].major = TTY_MAJOR;
-@@ -262,7 +264,7 @@
- if (info->ndev > 0)
- info->node[info->ndev-1].next = &info->node[info->ndev];
- info->ndev++;
--
-+
- return 0;
- }
-
-@@ -313,7 +315,10 @@
- return setup_serial(info, port, config.AssignedIRQ);
- }
- link->conf.Vcc = config.Vcc;
--
-+
-+ link->io.NumPorts1 = 8;
-+ link->io.NumPorts2 = 0;
-+
- /* First pass: look for a config entry that looks normal. */
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-@@ -340,7 +345,7 @@
- i = next_tuple(handle, &tuple, &parse);
- }
- }
--
-+
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
-@@ -352,8 +357,7 @@
- for (j = 0; j < 5; j++) {
- link->io.BasePort1 = base[j];
- link->io.IOAddrLines = base[j] ? 16 : 3;
-- i = CardServices(RequestIO, link->handle,
-- &link->io);
-+ i = CardServices(RequestIO, link->handle, &link->io);
- if (i == CS_SUCCESS) goto found_port;
- }
- }
-@@ -365,7 +369,7 @@
- cs_error(link->handle, RequestIO, i);
- return -1;
- }
--
-+
- i = CardServices(RequestIRQ, link->handle, &link->irq);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIRQ, i);
-@@ -390,8 +394,12 @@
- u_char buf[256];
- cisparse_t parse;
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
- int i, base2 = 0;
-
-+ CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
-@@ -433,12 +441,12 @@
- i = next_tuple(handle, &tuple, &parse);
- }
- }
--
-+
- if (i != CS_SUCCESS) {
-- cs_error(link->handle, RequestIO, i);
-- return -1;
-+ /* At worst, try to configure as a single port */
-+ return simple_config(link);
- }
--
-+
- i = CardServices(RequestIRQ, link->handle, &link->irq);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIRQ, i);
-@@ -454,14 +462,27 @@
- cs_error(link->handle, RequestConfiguration, i);
- return -1;
- }
--
-+
-+ /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-+ 8 registers are for the UART, the others are extra registers */
-+ if (info->manfid == MANFID_OXSEMI) {
-+ if (cf->index == 1 || cf->index == 3) {
-+ setup_serial(info, base2, link->irq.AssignedIRQ);
-+ outb(12,link->io.BasePort1+1);
-+ } else {
-+ setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
-+ outb(12,base2+1);
-+ }
-+ return 0;
-+ }
-+
- setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
- /* The Nokia cards are not really multiport cards */
- if (info->manfid == MANFID_NOKIA)
- return 0;
- for (i = 0; i < info->multi-1; i++)
- setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
--
-+
- return 0;
- }
-
-@@ -500,7 +521,7 @@
- }
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
--
-+
- /* Configure card */
- link->state |= DEV_CONFIG;
-
-@@ -508,8 +529,8 @@
- tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
- tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
- info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
--
-- /* Is this a multiport card? */
-+
-+ /* Scan list of known multiport card ID's */
- tuple.DesiredTuple = CISTPL_MANFID;
- if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
- info->manfid = le16_to_cpu(buf[0]);
-@@ -537,15 +558,15 @@
- info->multi = 2;
- }
- }
--
-+
- if (info->multi > 1)
- multi_config(link);
- else
- simple_config(link);
--
-+
- if (info->ndev == 0)
- goto failed;
--
-+
- if (info->manfid == MANFID_IBM) {
- conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
- CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
-@@ -562,6 +583,7 @@
- cs_error(link->handle, last_fn, last_ret);
- failed:
- serial_release((u_long)link);
-+ link->state &= ~DEV_CONFIG_PENDING;
-
- } /* serial_config */
-
-@@ -569,7 +591,7 @@
-
- After a card is removed, serial_release() will unregister the net
- device, and release the PCMCIA configuration.
--
-+
- ======================================================================*/
-
- void serial_release(u_long arg)
-@@ -577,7 +599,7 @@
- dev_link_t *link = (dev_link_t *)arg;
- serial_info_t *info = link->priv;
- int i;
--
-+
- DEBUG(0, "serial_release(0x%p)\n", link);
-
- for (i = 0; i < info->ndev; i++) {
-@@ -590,7 +612,7 @@
- CardServices(ReleaseIO, link->handle, &link->io);
- CardServices(ReleaseIRQ, link->handle, &link->irq);
- }
--
-+
- link->state &= ~DEV_CONFIG;
-
- } /* serial_release */
-@@ -601,7 +623,7 @@
- stuff to run after an event is received. A CARD_REMOVAL event
- also sets some flags to discourage the serial drivers from
- talking to the ports.
--
-+
- ======================================================================*/
-
- static int serial_event(event_t event, int priority,
-@@ -609,9 +631,9 @@
- {
- dev_link_t *link = args->client_data;
- serial_info_t *info = link->priv;
--
-+
- DEBUG(1, "serial_event(0x%06x)\n", event);
--
-+
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- link->state &= ~DEV_PRESENT;
-@@ -650,7 +672,7 @@
- if (serv.Revision != CS_RELEASE_CODE) {
- printk(KERN_NOTICE "serial_cs: Card Services release "
- "does not match!\n");
-- return -1;
-+ return -EINVAL;
- }
- register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
- return 0;
-diff -urN linux-2.4.18/drivers/input/Config.in linux-2.4.18-mh15/drivers/input/Config.in
---- linux-2.4.18/drivers/input/Config.in 2001-09-13 00:34:06.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/input/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -14,5 +14,6 @@
- fi
- dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
- dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
-+dep_tristate ' User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT
-
- endmenu
-diff -urN linux-2.4.18/drivers/input/keybdev.c linux-2.4.18-mh15/drivers/input/keybdev.c
---- linux-2.4.18/drivers/input/keybdev.c 2001-10-11 18:14:32.000000000 +0200
-+++ linux-2.4.18-mh15/drivers/input/keybdev.c 2004-08-01 16:26:23.000000000 +0200
-@@ -154,16 +154,18 @@
-
- static struct input_handler keybdev_handler;
-
-+static unsigned int ledstate = 0xff;
-+
- void keybdev_ledfunc(unsigned int led)
- {
- struct input_handle *handle;
-
-- for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-+ ledstate = led;
-
-+ for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
- input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
- input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02));
- input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04));
--
- }
- }
-
-@@ -202,6 +204,12 @@
-
- // printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
-
-+ if (ledstate != 0xff) {
-+ input_event(dev, EV_LED, LED_SCROLLL, !!(ledstate & 0x01));
-+ input_event(dev, EV_LED, LED_NUML, !!(ledstate & 0x02));
-+ input_event(dev, EV_LED, LED_CAPSL, !!(ledstate & 0x04));
-+ }
-+
- return handle;
- }
-
-diff -urN linux-2.4.18/drivers/input/Makefile linux-2.4.18-mh15/drivers/input/Makefile
---- linux-2.4.18/drivers/input/Makefile 2000-12-29 23:07:22.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/input/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -24,6 +24,7 @@
- obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
- obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
- obj-$(CONFIG_INPUT_EVDEV) += evdev.o
-+obj-$(CONFIG_INPUT_UINPUT) += uinput.o
-
- # The global Rules.make.
-
-diff -urN linux-2.4.18/drivers/input/uinput.c linux-2.4.18-mh15/drivers/input/uinput.c
---- linux-2.4.18/drivers/input/uinput.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/input/uinput.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,428 @@
-+/*
-+ * User level driver support for input subsystem
-+ *
-+ * Heavily based on evdev.c by Vojtech Pavlik
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
-+ *
-+ * Changes/Revisions:
-+ * 0.1 20/06/2002
-+ * - first public version
-+ */
-+
-+#include <linux/poll.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/input.h>
-+#include <linux/smp_lock.h>
-+#include <linux/fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/uinput.h>
-+
-+static int uinput_dev_open(struct input_dev *dev)
-+{
-+ return 0;
-+}
-+
-+static void uinput_dev_close(struct input_dev *dev)
-+{
-+}
-+
-+static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-+{
-+ struct uinput_device *udev;
-+
-+ udev = (struct uinput_device *)dev->private;
-+
-+ udev->buff[udev->head].type = type;
-+ udev->buff[udev->head].code = code;
-+ udev->buff[udev->head].value = value;
-+ do_gettimeofday(&udev->buff[udev->head].time);
-+ udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
-+
-+ wake_up_interruptible(&udev->waitq);
-+
-+ return 0;
-+}
-+
-+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
-+{
-+ return 0;
-+}
-+
-+static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
-+{
-+ return 0;
-+}
-+
-+static int uinput_create_device(struct uinput_device *udev)
-+{
-+ if (!udev->dev->name) {
-+ printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
-+ return -EINVAL;
-+ }
-+
-+ udev->dev->open = uinput_dev_open;
-+ udev->dev->close = uinput_dev_close;
-+ udev->dev->event = uinput_dev_event;
-+ udev->dev->upload_effect = uinput_dev_upload_effect;
-+ udev->dev->erase_effect = uinput_dev_erase_effect;
-+ udev->dev->private = udev;
-+
-+ init_waitqueue_head(&(udev->waitq));
-+
-+ input_register_device(udev->dev);
-+
-+ set_bit(UIST_CREATED, &(udev->state));
-+
-+ return 0;
-+}
-+
-+static int uinput_destroy_device(struct uinput_device *udev)
-+{
-+ if (!test_bit(UIST_CREATED, &(udev->state))) {
-+ printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
-+ return -EINVAL;
-+ }
-+
-+ input_unregister_device(udev->dev);
-+
-+ clear_bit(UIST_CREATED, &(udev->state));
-+
-+ return 0;
-+}
-+
-+static int uinput_open(struct inode *inode, struct file *file)
-+{
-+ struct uinput_device *newdev;
-+ struct input_dev *newinput;
-+
-+ newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
-+ if (!newdev)
-+ goto error;
-+ memset(newdev, 0, sizeof(struct uinput_device));
-+
-+ newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
-+ if (!newinput)
-+ goto cleanup;
-+ memset(newinput, 0, sizeof(struct input_dev));
-+
-+ newdev->dev = newinput;
-+
-+ file->private_data = newdev;
-+
-+ return 0;
-+cleanup:
-+ kfree(newdev);
-+error:
-+ return -ENOMEM;
-+}
-+
-+static int uinput_validate_absbits(struct input_dev *dev)
-+{
-+ unsigned int cnt;
-+ int retval = 0;
-+
-+ for (cnt = 0; cnt < ABS_MAX; cnt++) {
-+ if (!test_bit(cnt, dev->absbit))
-+ continue;
-+
-+ if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
-+ (dev->absmax[cnt] <= dev->absmin[cnt])) {
-+ printk(KERN_DEBUG
-+ "%s: invalid abs[%02x] min:%d max:%d\n",
-+ UINPUT_NAME, cnt,
-+ dev->absmin[cnt], dev->absmax[cnt]);
-+ retval = -EINVAL;
-+ break;
-+ }
-+
-+ if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
-+ (dev->absflat[cnt] > dev->absmax[cnt])) {
-+ printk(KERN_DEBUG
-+ "%s: absflat[%02x] out of range: %d "
-+ "(min:%d/max:%d)\n",
-+ UINPUT_NAME, cnt, dev->absflat[cnt],
-+ dev->absmin[cnt], dev->absmax[cnt]);
-+ retval = -EINVAL;
-+ break;
-+ }
-+ }
-+ return retval;
-+}
-+
-+static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
-+{
-+ struct uinput_user_dev *user_dev;
-+ struct input_dev *dev;
-+ struct uinput_device *udev;
-+ int size,
-+ retval;
-+
-+ retval = count;
-+
-+ udev = (struct uinput_device *)file->private_data;
-+ dev = udev->dev;
-+
-+ user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
-+ if (!user_dev) {
-+ retval = -ENOMEM;
-+ goto exit;
-+ }
-+
-+ if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
-+ retval = -EFAULT;
-+ goto exit;
-+ }
-+
-+ if (NULL != dev->name)
-+ kfree(dev->name);
-+
-+ size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
-+ dev->name = kmalloc(size, GFP_KERNEL);
-+ if (!dev->name) {
-+ retval = -ENOMEM;
-+ goto exit;
-+ }
-+
-+ strncpy(dev->name, user_dev->name, size);
-+ dev->idbus = user_dev->idbus;
-+ dev->idvendor = user_dev->idvendor;
-+ dev->idproduct = user_dev->idproduct;
-+ dev->idversion = user_dev->idversion;
-+ dev->ff_effects_max = user_dev->ff_effects_max;
-+
-+ size = sizeof(int) * (ABS_MAX + 1);
-+ memcpy(dev->absmax, user_dev->absmax, size);
-+ memcpy(dev->absmin, user_dev->absmin, size);
-+ memcpy(dev->absfuzz, user_dev->absfuzz, size);
-+ memcpy(dev->absflat, user_dev->absflat, size);
-+
-+ /* check if absmin/absmax/absfuzz/absflat are filled as
-+ * told in Documentation/input/input-programming.txt */
-+ if (test_bit(EV_ABS, dev->evbit)) {
-+ retval = uinput_validate_absbits(dev);
-+ if (retval < 0)
-+ kfree(dev->name);
-+ }
-+
-+exit:
-+ kfree(user_dev);
-+ return retval;
-+}
-+
-+static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
-+{
-+ struct uinput_device *udev = file->private_data;
-+
-+ if (test_bit(UIST_CREATED, &(udev->state))) {
-+ struct input_event ev;
-+
-+ if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
-+ return -EFAULT;
-+ input_event(udev->dev, ev.type, ev.code, ev.value);
-+ }
-+ else
-+ count = uinput_alloc_device(file, buffer, count);
-+
-+ return count;
-+}
-+
-+static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-+{
-+ struct uinput_device *udev = file->private_data;
-+ int retval = 0;
-+
-+ if (!test_bit(UIST_CREATED, &(udev->state)))
-+ return -ENODEV;
-+
-+ if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
-+ return -EAGAIN;
-+
-+ retval = wait_event_interruptible(udev->waitq,
-+ (udev->head != udev->tail) ||
-+ !test_bit(UIST_CREATED, &(udev->state)));
-+
-+ if (retval)
-+ return retval;
-+
-+ if (!test_bit(UIST_CREATED, &(udev->state)))
-+ return -ENODEV;
-+
-+ while ((udev->head != udev->tail) &&
-+ (retval + sizeof(struct input_event) <= count)) {
-+ if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
-+ sizeof(struct input_event))) return -EFAULT;
-+ udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
-+ retval += sizeof(struct input_event);
-+ }
-+
-+ return retval;
-+}
-+
-+static unsigned int uinput_poll(struct file *file, poll_table *wait)
-+{
-+ struct uinput_device *udev = file->private_data;
-+
-+ poll_wait(file, &udev->waitq, wait);
-+
-+ if (udev->head != udev->tail)
-+ return POLLIN | POLLRDNORM;
-+
-+ return 0;
-+}
-+
-+static int uinput_burn_device(struct uinput_device *udev)
-+{
-+ if (test_bit(UIST_CREATED, &(udev->state)))
-+ uinput_destroy_device(udev);
-+
-+ kfree(udev->dev);
-+ kfree(udev);
-+
-+ return 0;
-+}
-+
-+static int uinput_close(struct inode *inode, struct file *file)
-+{
-+ return uinput_burn_device((struct uinput_device *)file->private_data);
-+}
-+
-+static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int retval = 0;
-+ struct uinput_device *udev;
-+
-+ udev = (struct uinput_device *)file->private_data;
-+
-+ /* device attributes can not be changed after the device is created */
-+ if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
-+ return -EINVAL;
-+
-+ switch (cmd) {
-+ case UI_DEV_CREATE:
-+ retval = uinput_create_device(udev);
-+ break;
-+
-+ case UI_DEV_DESTROY:
-+ retval = uinput_destroy_device(udev);
-+ break;
-+
-+ case UI_SET_EVBIT:
-+ if (arg > EV_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->evbit);
-+ break;
-+
-+ case UI_SET_KEYBIT:
-+ if (arg > KEY_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->keybit);
-+ break;
-+
-+ case UI_SET_RELBIT:
-+ if (arg > REL_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->relbit);
-+ break;
-+
-+ case UI_SET_ABSBIT:
-+ if (arg > ABS_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->absbit);
-+ break;
-+
-+ case UI_SET_MSCBIT:
-+ if (arg > MSC_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->mscbit);
-+ break;
-+
-+ case UI_SET_LEDBIT:
-+ if (arg > LED_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->ledbit);
-+ break;
-+
-+ case UI_SET_SNDBIT:
-+ if (arg > SND_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->sndbit);
-+ break;
-+
-+ case UI_SET_FFBIT:
-+ if (arg > FF_MAX) {
-+ retval = -EINVAL;
-+ break;
-+ }
-+ set_bit(arg, udev->dev->ffbit);
-+ break;
-+
-+ default:
-+ retval = -EFAULT;
-+ }
-+ return retval;
-+}
-+
-+struct file_operations uinput_fops = {
-+ owner: THIS_MODULE,
-+ open: uinput_open,
-+ release: uinput_close,
-+ read: uinput_read,
-+ write: uinput_write,
-+ poll: uinput_poll,
-+ ioctl: uinput_ioctl,
-+};
-+
-+static struct miscdevice uinput_misc = {
-+ fops: &uinput_fops,
-+ minor: UINPUT_MINOR,
-+ name: UINPUT_NAME,
-+};
-+
-+static int __init uinput_init(void)
-+{
-+ return misc_register(&uinput_misc);
-+}
-+
-+static void __exit uinput_exit(void)
-+{
-+ misc_deregister(&uinput_misc);
-+}
-+
-+MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
-+MODULE_DESCRIPTION("User level driver support for input subsystem");
-+MODULE_LICENSE("GPL");
-+
-+module_init(uinput_init);
-+module_exit(uinput_exit);
-+
-diff -urN linux-2.4.18/drivers/isdn/avmb1/capidrv.c linux-2.4.18-mh15/drivers/isdn/avmb1/capidrv.c
---- linux-2.4.18/drivers/isdn/avmb1/capidrv.c 2001-12-21 18:41:54.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/isdn/avmb1/capidrv.c 2004-08-01 16:26:23.000000000 +0200
-@@ -514,13 +514,25 @@
-
- static void send_message(capidrv_contr * card, _cmsg * cmsg)
- {
-- struct sk_buff *skb;
-- size_t len;
-+ struct sk_buff *skb;
-+ size_t len;
-+ u16 err;
-+
- capi_cmsg2message(cmsg, cmsg->buf);
- len = CAPIMSG_LEN(cmsg->buf);
- skb = alloc_skb(len, GFP_ATOMIC);
-+ if(!skb) {
-+ printk(KERN_ERR "no skb len(%d) memory\n", len);
-+ return;
-+ }
- memcpy(skb_put(skb, len), cmsg->buf, len);
-- (*capifuncs->capi_put_message) (global.appid, skb);
-+ err = (*capifuncs->capi_put_message) (global.appid, skb);
-+ if (err) {
-+ printk(KERN_WARNING "%s: capi_put_message error: %04x\n",
-+ __FUNCTION__, err);
-+ kfree_skb(skb);
-+ return;
-+ }
- global.nsentctlpkt++;
- }
-
-@@ -2179,10 +2191,10 @@
- free_ncci(card, card->bchans[card->nbchan-1].nccip);
- if (card->bchans[card->nbchan-1].plcip)
- free_plci(card, card->bchans[card->nbchan-1].plcip);
-- if (card->plci_list)
-- printk(KERN_ERR "capidrv: bug in free_plci()\n");
- card->nbchan--;
- }
-+ if (card->plci_list)
-+ printk(KERN_ERR "capidrv: bug in free_plci()\n");
- kfree(card->bchans);
- card->bchans = 0;
-
-diff -urN linux-2.4.18/drivers/isdn/avmb1/kcapi.c linux-2.4.18-mh15/drivers/isdn/avmb1/kcapi.c
---- linux-2.4.18/drivers/isdn/avmb1/kcapi.c 2001-12-21 18:41:54.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/isdn/avmb1/kcapi.c 2004-08-01 16:26:23.000000000 +0200
-@@ -545,7 +545,13 @@
- static void notify_up(__u32 contr)
- {
- struct capi_interface_user *p;
-+ __u16 appl;
-
-+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-+ if (!VALID_APPLID(appl)) continue;
-+ if (APPL(appl)->releasing) continue;
-+ CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam);
-+ }
- printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
- spin_lock(&capi_users_lock);
- for (p = capi_users; p; p = p->next) {
-@@ -705,12 +711,16 @@
- nextpp = &(*pp)->next;
- }
- }
-- APPL(appl)->releasing--;
-- if (APPL(appl)->releasing <= 0) {
-- APPL(appl)->signal = 0;
-- APPL_MARK_FREE(appl);
-- printk(KERN_INFO "kcapi: appl %d down\n", appl);
-- }
-+ if (APPL(appl)->releasing) { /* only release if the application was marked for release */
-+ printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing);
-+ APPL(appl)->releasing--;
-+ if (APPL(appl)->releasing <= 0) {
-+ APPL(appl)->signal = 0;
-+ APPL_MARK_FREE(appl);
-+ printk(KERN_INFO "kcapi: appl %d down\n", appl);
-+ }
-+ } else
-+ printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr);
- }
- /*
- * ncci management
-@@ -863,16 +873,7 @@
-
- static void controllercb_ready(struct capi_ctr * card)
- {
-- __u16 appl;
--
- card->cardstate = CARD_RUNNING;
--
-- for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-- if (!VALID_APPLID(appl)) continue;
-- if (APPL(appl)->releasing) continue;
-- card->driver->register_appl(card, appl, &APPL(appl)->rparam);
-- }
--
- printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
- CARDNR(card), card->name);
-
-diff -urN linux-2.4.18/drivers/usb/Config.in linux-2.4.18-mh15/drivers/usb/Config.in
---- linux-2.4.18/drivers/usb/Config.in 2002-02-25 20:38:07.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/usb/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -31,7 +31,13 @@
-
- comment 'USB Device Class drivers'
- dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
--dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+ if [ "$CONFIG_BLUEZ" = "n" ]; then
-+ dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
-+ else
-+ comment ' USB Bluetooth can only be used with disabled Bluetooth subsystem'
-+ fi
-+fi
- if [ "$CONFIG_SCSI" = "n" ]; then
- comment ' SCSI support is needed for USB Storage'
- fi
-diff -urN linux-2.4.18/drivers/usb/hid-core.c linux-2.4.18-mh15/drivers/usb/hid-core.c
---- linux-2.4.18/drivers/usb/hid-core.c 2001-12-21 18:41:55.000000000 +0100
-+++ linux-2.4.18-mh15/drivers/usb/hid-core.c 2004-08-01 16:26:23.000000000 +0200
-@@ -217,6 +217,8 @@
-
- offset = report->size;
- report->size += parser->global.report_size * parser->global.report_count;
-+ if (usages < parser->global.report_count)
-+ usages = parser->global.report_count;
-
- if (usages == 0)
- return 0; /* ignore padding fields */
-diff -urN linux-2.4.18/include/linux/firmware.h linux-2.4.18-mh15/include/linux/firmware.h
---- linux-2.4.18/include/linux/firmware.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/include/linux/firmware.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,20 @@
-+#ifndef _LINUX_FIRMWARE_H
-+#define _LINUX_FIRMWARE_H
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#define FIRMWARE_NAME_MAX 30
-+struct firmware {
-+ size_t size;
-+ u8 *data;
-+};
-+int request_firmware (const struct firmware **fw, const char *name,
-+ const char *device);
-+int request_firmware_nowait (
-+ struct module *module,
-+ const char *name, const char *device, void *context,
-+ void (*cont)(const struct firmware *fw, void *context));
-+/* On 2.5 'device' is 'struct device *' */
-+
-+void release_firmware (const struct firmware *fw);
-+void register_firmware (const char *name, const u8 *data, size_t size);
-+#endif
-diff -urN linux-2.4.18/include/linux/input.h linux-2.4.18-mh15/include/linux/input.h
---- linux-2.4.18/include/linux/input.h 2001-09-13 00:34:06.000000000 +0200
-+++ linux-2.4.18-mh15/include/linux/input.h 2004-08-01 16:26:23.000000000 +0200
-@@ -468,6 +468,8 @@
- #define BUS_PCI 0x01
- #define BUS_ISAPNP 0x02
- #define BUS_USB 0x03
-+#define BUS_HIL 0x04
-+#define BUS_BLUETOOTH 0x05
-
- #define BUS_ISA 0x10
- #define BUS_I8042 0x11
-diff -urN linux-2.4.18/include/linux/kernel.h linux-2.4.18-mh15/include/linux/kernel.h
---- linux-2.4.18/include/linux/kernel.h 2002-02-25 20:38:13.000000000 +0100
-+++ linux-2.4.18-mh15/include/linux/kernel.h 2004-08-01 16:26:23.000000000 +0200
-@@ -11,6 +11,7 @@
- #include <linux/linkage.h>
- #include <linux/stddef.h>
- #include <linux/types.h>
-+#include <linux/compiler.h>
-
- /* Optimization barrier */
- /* The "volatile" is due to gcc bugs */
-@@ -181,4 +182,6 @@
- char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
- };
-
--#endif
-+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
-+
-+#endif /* _LINUX_KERNEL_H */
-diff -urN linux-2.4.18/include/linux/net.h linux-2.4.18-mh15/include/linux/net.h
---- linux-2.4.18/include/linux/net.h 2001-11-22 20:46:19.000000000 +0100
-+++ linux-2.4.18-mh15/include/linux/net.h 2004-08-01 16:26:23.000000000 +0200
-@@ -139,6 +139,7 @@
- extern int sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags);
- extern int sock_readv_writev(int type, struct inode * inode, struct file * file,
- const struct iovec * iov, long count, long size);
-+extern struct socket *sockfd_lookup(int fd, int *err);
-
- extern int net_ratelimit(void);
- extern unsigned long net_random(void);
-diff -urN linux-2.4.18/include/linux/uinput.h linux-2.4.18-mh15/include/linux/uinput.h
---- linux-2.4.18/include/linux/uinput.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/include/linux/uinput.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,79 @@
-+/*
-+ * User level driver support for input subsystem
-+ *
-+ * Heavily based on evdev.c by Vojtech Pavlik
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
-+ *
-+ * Changes/Revisions:
-+ * 0.1 20/06/2002
-+ * - first public version
-+ */
-+
-+#ifndef __UINPUT_H_
-+#define __UINPUT_H_
-+
-+#ifdef __KERNEL__
-+#define UINPUT_MINOR 223
-+#define UINPUT_NAME "uinput"
-+#define UINPUT_BUFFER_SIZE 16
-+
-+/* state flags => bit index for {set|clear|test}_bit ops */
-+#define UIST_CREATED 0
-+
-+struct uinput_device {
-+ struct input_dev *dev;
-+ unsigned long state;
-+ wait_queue_head_t waitq;
-+ unsigned char ready,
-+ head,
-+ tail;
-+ struct input_event buff[UINPUT_BUFFER_SIZE];
-+};
-+#endif /* __KERNEL__ */
-+
-+/* ioctl */
-+#define UINPUT_IOCTL_BASE 'U'
-+#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
-+#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
-+#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
-+#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
-+#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
-+#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
-+#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
-+#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
-+#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
-+#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
-+
-+#ifndef NBITS
-+#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
-+#endif /* NBITS */
-+
-+#define UINPUT_MAX_NAME_SIZE 80
-+struct uinput_user_dev {
-+ char name[UINPUT_MAX_NAME_SIZE];
-+ unsigned short idbus;
-+ unsigned short idvendor;
-+ unsigned short idproduct;
-+ unsigned short idversion;
-+ int ff_effects_max;
-+ int absmax[ABS_MAX + 1];
-+ int absmin[ABS_MAX + 1];
-+ int absfuzz[ABS_MAX + 1];
-+ int absflat[ABS_MAX + 1];
-+};
-+#endif /* __UINPUT_H_ */
-diff -urN linux-2.4.18/include/net/bluetooth/bluetooth.h linux-2.4.18-mh15/include/net/bluetooth/bluetooth.h
---- linux-2.4.18/include/net/bluetooth/bluetooth.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/bluetooth.h 2004-08-01 16:26:23.000000000 +0200
-@@ -23,7 +23,7 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __BLUETOOTH_H
-@@ -31,17 +31,64 @@
-
- #include <asm/types.h>
- #include <asm/byteorder.h>
-+#include <linux/poll.h>
-+#include <net/sock.h>
-
- #ifndef AF_BLUETOOTH
- #define AF_BLUETOOTH 31
- #define PF_BLUETOOTH AF_BLUETOOTH
- #endif
-
-+/* Reserv for core and drivers use */
-+#define BLUEZ_SKB_RESERVE 8
-+
-+#ifndef MIN
-+#define MIN(a,b) ((a) < (b) ? (a) : (b))
-+#endif
-+
- #define BTPROTO_L2CAP 0
- #define BTPROTO_HCI 1
-+#define BTPROTO_SCO 2
-+#define BTPROTO_RFCOMM 3
-+#define BTPROTO_BNEP 4
-+#define BTPROTO_CMTP 5
-+#define BTPROTO_HIDP 6
-
- #define SOL_HCI 0
- #define SOL_L2CAP 6
-+#define SOL_SCO 17
-+#define SOL_RFCOMM 18
-+
-+/* Debugging */
-+#ifdef CONFIG_BLUEZ_DEBUG
-+
-+#define HCI_CORE_DEBUG 1
-+#define HCI_SOCK_DEBUG 1
-+#define HCI_UART_DEBUG 1
-+#define HCI_USB_DEBUG 1
-+//#define HCI_DATA_DUMP 1
-+
-+#define L2CAP_DEBUG 1
-+#define SCO_DEBUG 1
-+#define AF_BLUETOOTH_DEBUG 1
-+
-+#endif /* CONFIG_BLUEZ_DEBUG */
-+
-+extern void bluez_dump(char *pref, __u8 *buf, int count);
-+
-+#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95
-+#define __func__ __FUNCTION__
-+#endif
-+
-+#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
-+#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
-+#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
-+
-+#ifdef HCI_DATA_DUMP
-+#define BT_DMP(buf, len) bluez_dump(__func__, buf, len)
-+#else
-+#define BT_DMP(D...)
-+#endif
-
- /* Connection and socket states */
- enum {
-@@ -50,6 +97,7 @@
- BT_BOUND,
- BT_LISTEN,
- BT_CONNECT,
-+ BT_CONNECT2,
- BT_CONFIG,
- BT_DISCONN,
- BT_CLOSED
-@@ -66,7 +114,8 @@
- __u8 b[6];
- } __attribute__((packed)) bdaddr_t;
-
--#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000")
-+#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
-
- /* Copy, swap, convert BD Address */
- static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
-@@ -82,6 +131,91 @@
- char *batostr(bdaddr_t *ba);
- bdaddr_t *strtoba(char *str);
-
-+/* Common socket structures and functions */
-+
-+#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo)
-+#define bluez_sk(pi) ((struct sock *) \
-+ ((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo)))
-+
-+struct bluez_pinfo {
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+
-+ struct list_head accept_q;
-+ struct sock *parent;
-+};
-+
-+struct bluez_sock_list {
-+ struct sock *head;
-+ rwlock_t lock;
-+};
-+
-+int bluez_sock_register(int proto, struct net_proto_family *ops);
-+int bluez_sock_unregister(int proto);
-+void bluez_sock_init(struct socket *sock, struct sock *sk);
-+void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
-+void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
-+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
-+uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
-+
-+void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
-+struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
-+
-+/* Skb helpers */
-+struct bluez_skb_cb {
-+ int incomming;
-+};
-+#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb))
-+
-+static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
-+{
-+ struct sk_buff *skb;
-+
-+ if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
-+ skb_reserve(skb, BLUEZ_SKB_RESERVE);
-+ bluez_cb(skb)->incomming = 0;
-+ }
-+ return skb;
-+}
-+
-+static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len,
-+ int nb, int *err)
-+{
-+ struct sk_buff *skb;
-+
-+ if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
-+ skb_reserve(skb, BLUEZ_SKB_RESERVE);
-+ bluez_cb(skb)->incomming = 0;
-+ }
-+
-+ return skb;
-+}
-+
-+static inline int skb_frags_no(struct sk_buff *skb)
-+{
-+ register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
-+ register int n = 1;
-+
-+ for (; frag; frag=frag->next, n++);
-+ return n;
-+}
-+
-+int hci_core_init(void);
-+int hci_core_cleanup(void);
-+int hci_sock_init(void);
-+int hci_sock_cleanup(void);
-+
- int bterr(__u16 code);
-
-+#ifndef MODULE_LICENSE
-+#define MODULE_LICENSE(x)
-+#endif
-+
-+#ifndef list_for_each_safe
-+#define list_for_each_safe(pos, n, head) \
-+ for (pos = (head)->next, n = pos->next; pos != (head); \
-+ pos = n, n = pos->next)
-+#endif
-+
- #endif /* __BLUETOOTH_H */
-diff -urN linux-2.4.18/include/net/bluetooth/bluez.h linux-2.4.18-mh15/include/net/bluetooth/bluez.h
---- linux-2.4.18/include/net/bluetooth/bluez.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/bluez.h 1970-01-01 01:00:00.000000000 +0100
-@@ -1,124 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef __IF_BLUEZ_H
--#define __IF_BLUEZ_H
--
--#include <net/sock.h>
--
--#define BLUEZ_MAX_PROTO 2
--
--/* Reserv for core and drivers use */
--#define BLUEZ_SKB_RESERVE 8
--
--#ifndef MIN
--#define MIN(a,b) ((a) < (b) ? (a) : (b))
--#endif
--
--/* Debugging */
--#ifdef BLUEZ_DEBUG
--
--#define HCI_CORE_DEBUG 1
--#define HCI_SOCK_DEBUG 1
--#define HCI_UART_DEBUG 1
--#define HCI_USB_DEBUG 1
--//#define HCI_DATA_DUMP 1
--
--#define L2CAP_DEBUG 1
--
--#endif /* BLUEZ_DEBUG */
--
--extern void bluez_dump(char *pref, __u8 *buf, int count);
--
--#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
--#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
--#define ERR(fmt, arg...) printk(KERN_ERR __FUNCTION__ ": " fmt "\n" , ## arg)
--
--#ifdef HCI_DATA_DUMP
--#define DMP(buf, len) bluez_dump(__FUNCTION__, buf, len)
--#else
--#define DMP(D...)
--#endif
--
--/* ----- Sockets ------ */
--struct bluez_sock_list {
-- struct sock *head;
-- rwlock_t lock;
--};
--
--extern int bluez_sock_register(int proto, struct net_proto_family *ops);
--extern int bluez_sock_unregister(int proto);
--
--extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
--extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
--
--/* ----- SKB helpers ----- */
--struct bluez_skb_cb {
-- int incomming;
--};
--#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb))
--
--static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
--{
-- struct sk_buff *skb;
--
-- if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
-- skb_reserve(skb, BLUEZ_SKB_RESERVE);
-- bluez_cb(skb)->incomming = 0;
-- }
-- return skb;
--}
--
--static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len,
-- int nb, int *err)
--{
-- struct sk_buff *skb;
--
-- if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
-- skb_reserve(skb, BLUEZ_SKB_RESERVE);
-- bluez_cb(skb)->incomming = 0;
-- }
--
-- return skb;
--}
--
--static inline int skb_frags_no(struct sk_buff *skb)
--{
-- register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
-- register int n = 1;
--
-- for (; frag; frag=frag->next, n++);
-- return n;
--}
--
--extern int hci_core_init(void);
--extern int hci_core_cleanup(void);
--extern int hci_sock_init(void);
--extern int hci_sock_cleanup(void);
--
--#endif /* __IF_BLUEZ_H */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_core.h linux-2.4.18-mh15/include/net/bluetooth/hci_core.h
---- linux-2.4.18/include/net/bluetooth/hci_core.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/hci_core.h 2004-08-01 16:26:23.000000000 +0200
-@@ -23,7 +23,7 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __HCI_CORE_H
-@@ -32,14 +32,12 @@
- #include <net/bluetooth/hci.h>
-
- /* HCI upper protocols */
--#define HCI_MAX_PROTO 1
- #define HCI_PROTO_L2CAP 0
-+#define HCI_PROTO_SCO 1
-
- #define HCI_INIT_TIMEOUT (HZ * 10)
-
--/* ----- Inquiry cache ----- */
--#define INQUIRY_CACHE_AGE_MAX (HZ*5) // 5 seconds
--#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds
-+/* HCI Core structures */
-
- struct inquiry_entry {
- struct inquiry_entry *next;
-@@ -53,111 +51,188 @@
- struct inquiry_entry *list;
- };
-
--static inline void inquiry_cache_init(struct inquiry_cache *cache)
--{
-- spin_lock_init(&cache->lock);
-- cache->list = NULL;
--}
-+struct conn_hash {
-+ struct list_head list;
-+ spinlock_t lock;
-+ unsigned int num;
-+};
-
--static inline void inquiry_cache_lock(struct inquiry_cache *cache)
--{
-- spin_lock(&cache->lock);
--}
-+struct hci_dev {
-+ struct list_head list;
-+ spinlock_t lock;
-+ atomic_t refcnt;
-
--static inline void inquiry_cache_unlock(struct inquiry_cache *cache)
--{
-- spin_unlock(&cache->lock);
--}
-+ char name[8];
-+ unsigned long flags;
-+ __u16 id;
-+ __u8 type;
-+ bdaddr_t bdaddr;
-+ __u8 features[8];
-
--static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache)
--{
-- spin_lock_bh(&cache->lock);
--}
-+ __u16 pkt_type;
-+ __u16 link_policy;
-+ __u16 link_mode;
-
--static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
--{
-- spin_unlock_bh(&cache->lock);
--}
-+ unsigned long quirks;
-
--static inline long inquiry_cache_age(struct inquiry_cache *cache)
--{
-- return jiffies - cache->timestamp;
--}
-+ atomic_t cmd_cnt;
-+ unsigned int acl_cnt;
-+ unsigned int sco_cnt;
-
--static inline long inquiry_entry_age(struct inquiry_entry *e)
--{
-- return jiffies - e->timestamp;
--}
--extern void inquiry_cache_flush(struct inquiry_cache *cache);
-+ unsigned int acl_mtu;
-+ unsigned int sco_mtu;
-+ unsigned int acl_pkts;
-+ unsigned int sco_pkts;
-
--struct hci_dev;
-+ unsigned long cmd_last_tx;
-+ unsigned long acl_last_tx;
-+ unsigned long sco_last_tx;
-+
-+ struct tasklet_struct cmd_task;
-+ struct tasklet_struct rx_task;
-+ struct tasklet_struct tx_task;
-+
-+ struct sk_buff_head rx_q;
-+ struct sk_buff_head raw_q;
-+ struct sk_buff_head cmd_q;
-+
-+ struct sk_buff *sent_cmd;
-+
-+ struct semaphore req_lock;
-+ wait_queue_head_t req_wait_q;
-+ __u32 req_status;
-+ __u32 req_result;
-+
-+ struct inquiry_cache inq_cache;
-+ struct conn_hash conn_hash;
-+
-+ struct hci_dev_stats stat;
-+
-+ void *driver_data;
-+ void *core_data;
-+
-+ atomic_t promisc;
-+
-+ int (*open)(struct hci_dev *hdev);
-+ int (*close)(struct hci_dev *hdev);
-+ int (*flush)(struct hci_dev *hdev);
-+ int (*send)(struct sk_buff *skb);
-+ void (*destruct)(struct hci_dev *hdev);
-+ int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
-+};
-
--/* ----- HCI Connections ----- */
- struct hci_conn {
- struct list_head list;
-+
-+ atomic_t refcnt;
-+ spinlock_t lock;
-+
- bdaddr_t dst;
- __u16 handle;
-+ __u16 state;
- __u8 type;
-- unsigned int sent;
-+ __u8 out;
-+ __u32 link_mode;
-+ unsigned long pend;
-+
-+ unsigned int sent;
-+
-+ struct sk_buff_head data_q;
-
-+ struct timer_list timer;
-+
- struct hci_dev *hdev;
- void *l2cap_data;
-+ void *sco_data;
- void *priv;
-
-- struct sk_buff_head data_q;
-+ struct hci_conn *link;
- };
-
--struct conn_hash {
-- struct list_head list;
-- spinlock_t lock;
-- unsigned int num;
--};
-+extern struct hci_proto *hci_proto[];
-+extern struct list_head hdev_list;
-+extern rwlock_t hdev_list_lock;
-+
-+/* ----- Inquiry cache ----- */
-+#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds
-+#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds
-+
-+#define inquiry_cache_lock(c) spin_lock(&c->lock)
-+#define inquiry_cache_unlock(c) spin_unlock(&c->lock)
-+#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
-+#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
-
--static inline void conn_hash_init(struct conn_hash *h)
-+static inline void inquiry_cache_init(struct hci_dev *hdev)
- {
-- INIT_LIST_HEAD(&h->list);
-- spin_lock_init(&h->lock);
-- h->num = 0;
-+ struct inquiry_cache *c = &hdev->inq_cache;
-+ spin_lock_init(&c->lock);
-+ c->list = NULL;
- }
-
--static inline void conn_hash_lock(struct conn_hash *h)
-+static inline int inquiry_cache_empty(struct hci_dev *hdev)
- {
-- spin_lock(&h->lock);
-+ struct inquiry_cache *c = &hdev->inq_cache;
-+ return (c->list == NULL);
- }
-
--static inline void conn_hash_unlock(struct conn_hash *h)
-+static inline long inquiry_cache_age(struct hci_dev *hdev)
- {
-- spin_unlock(&h->lock);
-+ struct inquiry_cache *c = &hdev->inq_cache;
-+ return jiffies - c->timestamp;
- }
-
--static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
-+static inline long inquiry_entry_age(struct inquiry_entry *e)
- {
-- list_add(&c->list, &h->list);
-- h->num++;
-+ return jiffies - e->timestamp;
- }
-
--static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
-+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
-+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info);
-+void inquiry_cache_flush(struct hci_dev *hdev);
-+int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
-+
-+/* ----- HCI Connections ----- */
-+enum {
-+ HCI_CONN_AUTH_PEND,
-+ HCI_CONN_ENCRYPT_PEND
-+};
-+
-+#define hci_conn_lock(c) spin_lock(&c->lock)
-+#define hci_conn_unlock(c) spin_unlock(&c->lock)
-+#define hci_conn_lock_bh(c) spin_lock_bh(&c->lock)
-+#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock)
-+
-+#define conn_hash_lock(d) spin_lock(&d->conn_hash->lock)
-+#define conn_hash_unlock(d) spin_unlock(&d->conn_hash->lock)
-+#define conn_hash_lock_bh(d) spin_lock_bh(&d->conn_hash->lock)
-+#define conn_hash_unlock_bh(d) spin_unlock_bh(&d->conn_hash->lock)
-+
-+static inline void conn_hash_init(struct hci_dev *hdev)
- {
-- conn_hash_lock(h);
-- __conn_hash_add(h, handle, c);
-- conn_hash_unlock(h);
-+ struct conn_hash *h = &hdev->conn_hash;
-+ INIT_LIST_HEAD(&h->list);
-+ spin_lock_init(&h->lock);
-+ h->num = 0;
- }
-
--static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c)
-+static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
- {
-- list_del(&c->list);
-- h->num--;
-+ struct conn_hash *h = &hdev->conn_hash;
-+ list_add(&c->list, &h->list);
-+ h->num++;
- }
-
--static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c)
-+static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
- {
-- conn_hash_lock(h);
-- __conn_hash_del(h, c);
-- conn_hash_unlock(h);
-+ struct conn_hash *h = &hdev->conn_hash;
-+ list_del(&c->list);
-+ h->num--;
- }
-
--static inline struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
-+static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev,
-+ __u16 handle)
- {
-+ register struct conn_hash *h = &hdev->conn_hash;
- register struct list_head *p;
- register struct hci_conn *c;
-
-@@ -169,101 +244,97 @@
- return NULL;
- }
-
--static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle)
-+static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev,
-+ __u8 type, bdaddr_t *ba)
- {
-- struct hci_conn *conn;
-+ register struct conn_hash *h = &hdev->conn_hash;
-+ register struct list_head *p;
-+ register struct hci_conn *c;
-
-- conn_hash_lock(h);
-- conn = __conn_hash_lookup(h, handle);
-- conn_hash_unlock(h);
-- return conn;
-+ list_for_each(p, &h->list) {
-+ c = list_entry(p, struct hci_conn, list);
-+ if (c->type == type && !bacmp(&c->dst, ba))
-+ return c;
-+ }
-+ return NULL;
- }
-
--/* ----- HCI Devices ----- */
--struct hci_dev {
-- atomic_t refcnt;
--
-- char name[8];
-- __u32 flags;
-- __u16 id;
-- __u8 type;
-- bdaddr_t bdaddr;
-- __u8 features[8];
--
-- __u16 pkt_type;
--
-- atomic_t cmd_cnt;
-- unsigned int acl_cnt;
-- unsigned int sco_cnt;
--
-- unsigned int acl_mtu;
-- unsigned int sco_mtu;
-- unsigned int acl_max;
-- unsigned int sco_max;
--
-- void *driver_data;
-- void *l2cap_data;
-- void *priv;
--
-- struct tasklet_struct cmd_task;
-- struct tasklet_struct rx_task;
-- struct tasklet_struct tx_task;
--
-- struct sk_buff_head rx_q;
-- struct sk_buff_head raw_q;
-- struct sk_buff_head cmd_q;
--
-- struct sk_buff *sent_cmd;
-+void hci_acl_connect(struct hci_conn *conn);
-+void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
-+void hci_add_sco(struct hci_conn *conn, __u16 handle);
-
-- struct semaphore req_lock;
-- wait_queue_head_t req_wait_q;
-- __u32 req_status;
-- __u32 req_result;
-+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
-+int hci_conn_del(struct hci_conn *conn);
-+void hci_conn_hash_flush(struct hci_dev *hdev);
-
-- struct inquiry_cache inq_cache;
-+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
-+int hci_conn_auth(struct hci_conn *conn);
-+int hci_conn_encrypt(struct hci_conn *conn);
-
-- struct conn_hash conn_hash;
--
-- struct hci_dev_stats stat;
--
-- int (*open)(struct hci_dev *hdev);
-- int (*close)(struct hci_dev *hdev);
-- int (*flush)(struct hci_dev *hdev);
-- int (*send)(struct sk_buff *skb);
--};
-+static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout)
-+{
-+ mod_timer(&conn->timer, jiffies + timeout);
-+}
-
--static inline void hci_dev_hold(struct hci_dev *hdev)
-+static inline void hci_conn_del_timer(struct hci_conn *conn)
- {
-- atomic_inc(&hdev->refcnt);
-+ del_timer(&conn->timer);
- }
-
--static inline void hci_dev_put(struct hci_dev *hdev)
-+static inline void hci_conn_hold(struct hci_conn *conn)
- {
-- atomic_dec(&hdev->refcnt);
-+ atomic_inc(&conn->refcnt);
-+ hci_conn_del_timer(conn);
- }
-
--extern struct hci_dev *hci_dev_get(int index);
--extern int hci_register_dev(struct hci_dev *hdev);
--extern int hci_unregister_dev(struct hci_dev *hdev);
--extern int hci_dev_open(__u16 dev);
--extern int hci_dev_close(__u16 dev);
--extern int hci_dev_reset(__u16 dev);
--extern int hci_dev_reset_stat(__u16 dev);
--extern int hci_dev_info(unsigned long arg);
--extern int hci_dev_list(unsigned long arg);
--extern int hci_dev_setscan(unsigned long arg);
--extern int hci_dev_setauth(unsigned long arg);
--extern int hci_dev_setptype(unsigned long arg);
--extern int hci_conn_list(unsigned long arg);
--extern int hci_inquiry(unsigned long arg);
-+static inline void hci_conn_put(struct hci_conn *conn)
-+{
-+ if (atomic_dec_and_test(&conn->refcnt)) {
-+ if (conn->type == ACL_LINK) {
-+ unsigned long timeo = (conn->out) ?
-+ HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2;
-+ hci_conn_set_timer(conn, timeo);
-+ } else
-+ hci_conn_set_timer(conn, HZ / 100);
-+ }
-+}
-
--extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
--extern __u32 hci_dev_getmode(struct hci_dev *hdev);
-+/* ----- HCI Devices ----- */
-+static inline void hci_dev_put(struct hci_dev *d)
-+{
-+ if (atomic_dec_and_test(&d->refcnt))
-+ d->destruct(d);
-+}
-+#define hci_dev_hold(d) atomic_inc(&d->refcnt)
-+
-+#define hci_dev_lock(d) spin_lock(&d->lock)
-+#define hci_dev_unlock(d) spin_unlock(&d->lock)
-+#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock)
-+#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock)
-+
-+struct hci_dev *hci_dev_get(int index);
-+struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
-+int hci_register_dev(struct hci_dev *hdev);
-+int hci_unregister_dev(struct hci_dev *hdev);
-+int hci_suspend_dev(struct hci_dev *hdev);
-+int hci_resume_dev(struct hci_dev *hdev);
-+int hci_dev_open(__u16 dev);
-+int hci_dev_close(__u16 dev);
-+int hci_dev_reset(__u16 dev);
-+int hci_dev_reset_stat(__u16 dev);
-+int hci_dev_cmd(unsigned int cmd, unsigned long arg);
-+int hci_get_dev_list(unsigned long arg);
-+int hci_get_dev_info(unsigned long arg);
-+int hci_get_conn_list(unsigned long arg);
-+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg);
-+int hci_inquiry(unsigned long arg);
-
--extern int hci_recv_frame(struct sk_buff *skb);
-+int hci_recv_frame(struct sk_buff *skb);
-+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
-
- /* ----- LMP capabilities ----- */
- #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
-+#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
-
- /* ----- HCI tasks ----- */
- static inline void hci_sched_cmd(struct hci_dev *hdev)
-@@ -284,43 +355,130 @@
- /* ----- HCI protocols ----- */
- struct hci_proto {
- char *name;
-- __u32 id;
-- __u32 flags;
-+ unsigned int id;
-+ unsigned long flags;
-
- void *priv;
-
-- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr);
-- int (*connect_cfm) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
-+ int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
-+ int (*connect_cfm) (struct hci_conn *conn, __u8 status);
- int (*disconn_ind) (struct hci_conn *conn, __u8 reason);
-- int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
-+ int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
- int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
-+ int (*auth_cfm) (struct hci_conn *conn, __u8 status);
-+ int (*encrypt_cfm) (struct hci_conn *conn, __u8 status);
- };
-
--extern int hci_register_proto(struct hci_proto *hproto);
--extern int hci_unregister_proto(struct hci_proto *hproto);
--extern int hci_register_notifier(struct notifier_block *nb);
--extern int hci_unregister_notifier(struct notifier_block *nb);
--extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
--extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
--extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
--extern int hci_send_raw(struct sk_buff *skb);
--extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
--extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
-+static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+ register struct hci_proto *hp;
-+ int mask = 0;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->connect_ind)
-+ mask |= hp->connect_ind(hdev, bdaddr, type);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->connect_ind)
-+ mask |= hp->connect_ind(hdev, bdaddr, type);
-+
-+ return mask;
-+}
-+
-+static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->connect_cfm)
-+ hp->connect_cfm(conn, status);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->connect_cfm)
-+ hp->connect_cfm(conn, status);
-+}
-+
-+static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->disconn_ind)
-+ hp->disconn_ind(conn, reason);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->disconn_ind)
-+ hp->disconn_ind(conn, reason);
-+}
-+
-+static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->auth_cfm)
-+ hp->auth_cfm(conn, status);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->auth_cfm)
-+ hp->auth_cfm(conn, status);
-+}
-+
-+static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->encrypt_cfm)
-+ hp->encrypt_cfm(conn, status);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->encrypt_cfm)
-+ hp->encrypt_cfm(conn, status);
-+}
-+
-+int hci_register_proto(struct hci_proto *hproto);
-+int hci_unregister_proto(struct hci_proto *hproto);
-+int hci_register_notifier(struct notifier_block *nb);
-+int hci_unregister_notifier(struct notifier_block *nb);
-+
-+int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
-+int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
-+int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
-+
-+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
-+
-+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
-
- /* ----- HCI Sockets ----- */
--extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
-+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
-
- /* HCI info for socket */
--#define hci_pi(sk) ((struct hci_pinfo *) &sk->protinfo)
-+#define hci_pi(sk) ((struct hci_pinfo *) &sk->tp_pinfo)
- struct hci_pinfo {
- struct hci_dev *hdev;
- struct hci_filter filter;
- __u32 cmsg_mask;
- };
-
-+/* HCI security filter */
-+#define HCI_SFLT_MAX_OGF 5
-+
-+struct hci_sec_filter {
-+ __u32 type_mask;
-+ __u32 event_mask[2];
-+ __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
-+};
-+
- /* ----- HCI requests ----- */
- #define HCI_REQ_DONE 0
- #define HCI_REQ_PEND 1
- #define HCI_REQ_CANCELED 2
-
-+#define hci_req_lock(d) down(&d->req_lock)
-+#define hci_req_unlock(d) up(&d->req_lock)
-+
-+void hci_req_complete(struct hci_dev *hdev, int result);
-+void hci_req_cancel(struct hci_dev *hdev, int err);
-+
- #endif /* __HCI_CORE_H */
-diff -urN linux-2.4.18/include/net/bluetooth/hci.h linux-2.4.18-mh15/include/net/bluetooth/hci.h
---- linux-2.4.18/include/net/bluetooth/hci.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/hci.h 2004-08-01 16:26:23.000000000 +0200
-@@ -23,59 +23,80 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __HCI_H
- #define __HCI_H
-
--#include <asm/byteorder.h>
--
--#define HCI_MAX_DEV 8
--#define HCI_MAX_FRAME_SIZE 2048
-+#define HCI_MAX_ACL_SIZE 1024
-+#define HCI_MAX_SCO_SIZE 255
-+#define HCI_MAX_EVENT_SIZE 260
-+#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
-
- /* HCI dev events */
- #define HCI_DEV_REG 1
- #define HCI_DEV_UNREG 2
- #define HCI_DEV_UP 3
- #define HCI_DEV_DOWN 4
-+#define HCI_DEV_SUSPEND 5
-+#define HCI_DEV_RESUME 6
-
- /* HCI device types */
--#define HCI_UART 0
-+#define HCI_VHCI 0
- #define HCI_USB 1
--#define HCI_VHCI 2
--
--/* HCI device modes */
--#define HCI_NORMAL 0x0001
--#define HCI_RAW 0x0002
--#define HCI_MODE_MASK (HCI_NORMAL | HCI_RAW)
--#define HCI_SOCK 0x1000
--
--/* HCI device states */
--#define HCI_INIT 0x0010
--#define HCI_UP 0x0020
--#define HCI_RUNNING 0x0040
-+#define HCI_PCCARD 2
-+#define HCI_UART 3
-+#define HCI_RS232 4
-+#define HCI_PCI 5
-+
-+/* HCI device quirks */
-+enum {
-+ HCI_QUIRK_RESET_ON_INIT
-+};
-
- /* HCI device flags */
--#define HCI_PSCAN 0x0100
--#define HCI_ISCAN 0x0200
--#define HCI_AUTH 0x0400
-+enum {
-+ HCI_UP,
-+ HCI_INIT,
-+ HCI_RUNNING,
-+
-+ HCI_PSCAN,
-+ HCI_ISCAN,
-+ HCI_AUTH,
-+ HCI_ENCRYPT,
-+ HCI_INQUIRY,
-+
-+ HCI_RAW
-+};
-
--/* HCI Ioctl defines */
-+/* HCI ioctl defines */
- #define HCIDEVUP _IOW('H', 201, int)
- #define HCIDEVDOWN _IOW('H', 202, int)
- #define HCIDEVRESET _IOW('H', 203, int)
--#define HCIRESETSTAT _IOW('H', 204, int)
--#define HCIGETINFO _IOR('H', 205, int)
--#define HCIGETDEVLIST _IOR('H', 206, int)
--#define HCISETRAW _IOW('H', 207, int)
--#define HCISETSCAN _IOW('H', 208, int)
--#define HCISETAUTH _IOW('H', 209, int)
--#define HCIINQUIRY _IOR('H', 210, int)
--#define HCISETPTYPE _IOW('H', 211, int)
-+#define HCIDEVRESTAT _IOW('H', 204, int)
-+
-+#define HCIGETDEVLIST _IOR('H', 210, int)
-+#define HCIGETDEVINFO _IOR('H', 211, int)
- #define HCIGETCONNLIST _IOR('H', 212, int)
-+#define HCIGETCONNINFO _IOR('H', 213, int)
-
--#ifndef __NO_HCI_DEFS
-+#define HCISETRAW _IOW('H', 220, int)
-+#define HCISETSCAN _IOW('H', 221, int)
-+#define HCISETAUTH _IOW('H', 222, int)
-+#define HCISETENCRYPT _IOW('H', 223, int)
-+#define HCISETPTYPE _IOW('H', 224, int)
-+#define HCISETLINKPOL _IOW('H', 225, int)
-+#define HCISETLINKMODE _IOW('H', 226, int)
-+#define HCISETACLMTU _IOW('H', 227, int)
-+#define HCISETSCOMTU _IOW('H', 228, int)
-+
-+#define HCIINQUIRY _IOR('H', 240, int)
-+
-+/* HCI timeouts */
-+#define HCI_CONN_TIMEOUT (HZ * 40)
-+#define HCI_DISCONN_TIMEOUT (HZ * 2)
-+#define HCI_CONN_IDLE_TIMEOUT (HZ * 60)
-
- /* HCI Packet types */
- #define HCI_COMMAND_PKT 0x01
-@@ -92,11 +113,18 @@
- #define HCI_DH3 0x0800
- #define HCI_DH5 0x8000
-
-+#define HCI_HV1 0x0020
-+#define HCI_HV2 0x0040
-+#define HCI_HV3 0x0080
-+
-+#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3)
-+#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK)
-+
- /* ACL flags */
--#define ACL_CONT 0x0001
--#define ACL_START 0x0002
--#define ACL_ACTIVE_BCAST 0x0010
--#define ACL_PICO_BCAST 0x0020
-+#define ACL_CONT 0x01
-+#define ACL_START 0x02
-+#define ACL_ACTIVE_BCAST 0x04
-+#define ACL_PICO_BCAST 0x08
-
- /* Baseband links */
- #define SCO_LINK 0x00
-@@ -125,6 +153,20 @@
- #define LMP_PSCHEME 0x02
- #define LMP_PCONTROL 0x04
-
-+/* Link policies */
-+#define HCI_LP_RSWITCH 0x0001
-+#define HCI_LP_HOLD 0x0002
-+#define HCI_LP_SNIFF 0x0004
-+#define HCI_LP_PARK 0x0008
-+
-+/* Link mode */
-+#define HCI_LM_ACCEPT 0x8000
-+#define HCI_LM_MASTER 0x0001
-+#define HCI_LM_AUTH 0x0002
-+#define HCI_LM_ENCRYPT 0x0004
-+#define HCI_LM_TRUSTED 0x0008
-+#define HCI_LM_RELIABLE 0x0010
-+
- /* ----- HCI Commands ----- */
- /* OGF & OCF values */
-
-@@ -137,9 +179,10 @@
- __u8 hci_ver;
- __u16 hci_rev;
- __u8 lmp_ver;
-- __u16 man_name;
-- __u16 lmp_sub;
-+ __u16 manufacturer;
-+ __u16 lmp_subver;
- } __attribute__ ((packed)) read_local_version_rp;
-+#define READ_LOCAL_VERSION_RP_SIZE 9
-
- #define OCF_READ_LOCAL_FEATURES 0x0003
- typedef struct {
-@@ -165,18 +208,24 @@
- /* Host Controller and Baseband */
- #define OGF_HOST_CTL 0x03
- #define OCF_RESET 0x0003
-+#define OCF_READ_AUTH_ENABLE 0x001F
- #define OCF_WRITE_AUTH_ENABLE 0x0020
-- #define AUTH_DISABLED 0x00
-- #define AUTH_ENABLED 0x01
-+ #define AUTH_DISABLED 0x00
-+ #define AUTH_ENABLED 0x01
-+
-+#define OCF_READ_ENCRYPT_MODE 0x0021
-+#define OCF_WRITE_ENCRYPT_MODE 0x0022
-+ #define ENCRYPT_DISABLED 0x00
-+ #define ENCRYPT_P2P 0x01
-+ #define ENCRYPT_BOTH 0x02
-
- #define OCF_WRITE_CA_TIMEOUT 0x0016
- #define OCF_WRITE_PG_TIMEOUT 0x0018
-
- #define OCF_WRITE_SCAN_ENABLE 0x001A
-- #define SCANS_DISABLED 0x00
-- #define IS_ENA_PS_DIS 0x01
-- #define IS_DIS_PS_ENA 0x02
-- #define IS_ENA_PS_ENA 0x03
-+ #define SCAN_DISABLED 0x00
-+ #define SCAN_INQUIRY 0x01
-+ #define SCAN_PAGE 0x02
-
- #define OCF_SET_EVENT_FLT 0x0005
- typedef struct {
-@@ -226,9 +275,18 @@
- } __attribute__ ((packed)) write_class_of_dev_cp;
- #define WRITE_CLASS_OF_DEV_CP_SIZE 3
-
-+#define OCF_HOST_BUFFER_SIZE 0x0033
-+typedef struct {
-+ __u16 acl_mtu;
-+ __u8 sco_mtu;
-+ __u16 acl_max_pkt;
-+ __u16 sco_max_pkt;
-+} __attribute__ ((packed)) host_buffer_size_cp;
-+#define HOST_BUFFER_SIZE_CP_SIZE 7
-+
- /* Link Control */
- #define OGF_LINK_CTL 0x01
--#define OCF_CREATE_CONN 0x0005
-+#define OCF_CREATE_CONN 0x0005
- typedef struct {
- bdaddr_t bdaddr;
- __u16 pkt_type;
-@@ -246,6 +304,13 @@
- } __attribute__ ((packed)) accept_conn_req_cp;
- #define ACCEPT_CONN_REQ_CP_SIZE 7
-
-+#define OCF_REJECT_CONN_REQ 0x000a
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 reason;
-+} __attribute__ ((packed)) reject_conn_req_cp;
-+#define REJECT_CONN_REQ_CP_SIZE 7
-+
- #define OCF_DISCONNECT 0x0006
- typedef struct {
- __u16 handle;
-@@ -253,17 +318,142 @@
- } __attribute__ ((packed)) disconnect_cp;
- #define DISCONNECT_CP_SIZE 3
-
-+#define OCF_ADD_SCO 0x0007
-+typedef struct {
-+ __u16 handle;
-+ __u16 pkt_type;
-+} __attribute__ ((packed)) add_sco_cp;
-+#define ADD_SCO_CP_SIZE 4
-+
- #define OCF_INQUIRY 0x0001
- typedef struct {
- __u8 lap[3];
-- __u8 lenght;
-+ __u8 length;
- __u8 num_rsp;
- } __attribute__ ((packed)) inquiry_cp;
- #define INQUIRY_CP_SIZE 5
-
--#define OGF_LINK_POLICY 0x02 /* Link Policy */
-+typedef struct {
-+ __u8 status;
-+ bdaddr_t bdaddr;
-+} __attribute__ ((packed)) status_bdaddr_rp;
-+#define STATUS_BDADDR_RP_SIZE 7
-+
-+#define OCF_INQUIRY_CANCEL 0x0002
-+
-+#define OCF_LINK_KEY_REPLY 0x000B
-+#define OCF_LINK_KEY_NEG_REPLY 0x000C
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 link_key[16];
-+} __attribute__ ((packed)) link_key_reply_cp;
-+#define LINK_KEY_REPLY_CP_SIZE 22
-+
-+#define OCF_PIN_CODE_REPLY 0x000D
-+#define OCF_PIN_CODE_NEG_REPLY 0x000E
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 pin_len;
-+ __u8 pin_code[16];
-+} __attribute__ ((packed)) pin_code_reply_cp;
-+#define PIN_CODE_REPLY_CP_SIZE 23
-+
-+#define OCF_CHANGE_CONN_PTYPE 0x000F
-+typedef struct {
-+ __u16 handle;
-+ __u16 pkt_type;
-+} __attribute__ ((packed)) change_conn_ptype_cp;
-+#define CHANGE_CONN_PTYPE_CP_SIZE 4
-+
-+#define OCF_AUTH_REQUESTED 0x0011
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) auth_requested_cp;
-+#define AUTH_REQUESTED_CP_SIZE 2
-+
-+#define OCF_SET_CONN_ENCRYPT 0x0013
-+typedef struct {
-+ __u16 handle;
-+ __u8 encrypt;
-+} __attribute__ ((packed)) set_conn_encrypt_cp;
-+#define SET_CONN_ENCRYPT_CP_SIZE 3
-+
-+#define OCF_REMOTE_NAME_REQ 0x0019
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 pscan_rep_mode;
-+ __u8 pscan_mode;
-+ __u16 clock_offset;
-+} __attribute__ ((packed)) remote_name_req_cp;
-+#define REMOTE_NAME_REQ_CP_SIZE 10
-+
-+#define OCF_READ_REMOTE_FEATURES 0x001B
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) read_remote_features_cp;
-+#define READ_REMOTE_FEATURES_CP_SIZE 2
-+
-+#define OCF_READ_REMOTE_VERSION 0x001D
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) read_remote_version_cp;
-+#define READ_REMOTE_VERSION_CP_SIZE 2
-+
-+/* Link Policy */
-+#define OGF_LINK_POLICY 0x02
-+#define OCF_ROLE_DISCOVERY 0x0009
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) role_discovery_cp;
-+#define ROLE_DISCOVERY_CP_SIZE 2
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 role;
-+} __attribute__ ((packed)) role_discovery_rp;
-+#define ROLE_DISCOVERY_RP_SIZE 4
-+
-+#define OCF_READ_LINK_POLICY 0x000C
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) read_link_policy_cp;
-+#define READ_LINK_POLICY_CP_SIZE 2
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u16 policy;
-+} __attribute__ ((packed)) read_link_policy_rp;
-+#define READ_LINK_POLICY_RP_SIZE 5
-
--/* --------- HCI Events --------- */
-+#define OCF_SWITCH_ROLE 0x000B
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 role;
-+} __attribute__ ((packed)) switch_role_cp;
-+#define SWITCH_ROLE_CP_SIZE 7
-+
-+#define OCF_WRITE_LINK_POLICY 0x000D
-+typedef struct {
-+ __u16 handle;
-+ __u16 policy;
-+} __attribute__ ((packed)) write_link_policy_cp;
-+#define WRITE_LINK_POLICY_CP_SIZE 4
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+} __attribute__ ((packed)) write_link_policy_rp;
-+#define WRITE_LINK_POLICY_RP_SIZE 3
-+
-+/* Status params */
-+#define OGF_STATUS_PARAM 0x05
-+
-+/* Testing commands */
-+#define OGF_TESTING_CMD 0x3e
-+
-+/* Vendor specific commands */
-+#define OGF_VENDOR_CMD 0x3f
-+
-+/* ---- HCI Events ---- */
- #define EVT_INQUIRY_COMPLETE 0x01
-
- #define EVT_INQUIRY_RESULT 0x02
-@@ -272,11 +462,22 @@
- __u8 pscan_rep_mode;
- __u8 pscan_period_mode;
- __u8 pscan_mode;
-- __u8 class[3];
-+ __u8 dev_class[3];
- __u16 clock_offset;
- } __attribute__ ((packed)) inquiry_info;
- #define INQUIRY_INFO_SIZE 14
-
-+#define EVT_INQUIRY_RESULT_WITH_RSSI 0x22
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 pscan_rep_mode;
-+ __u8 pscan_period_mode;
-+ __u8 dev_class[3];
-+ __u16 clock_offset;
-+ __s8 rssi;
-+} __attribute__ ((packed)) inquiry_info_with_rssi;
-+#define INQUIRY_INFO_WITH_RSSI_SIZE 14
-+
- #define EVT_CONN_COMPLETE 0x03
- typedef struct {
- __u8 status;
-@@ -303,6 +504,44 @@
- } __attribute__ ((packed)) evt_disconn_complete;
- #define EVT_DISCONN_COMPLETE_SIZE 4
-
-+#define EVT_AUTH_COMPLETE 0x06
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+} __attribute__ ((packed)) evt_auth_complete;
-+#define EVT_AUTH_COMPLETE_SIZE 3
-+
-+#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07
-+typedef struct {
-+ __u8 status;
-+ bdaddr_t bdaddr;
-+ __u8 name[248];
-+} __attribute__ ((packed)) evt_remote_name_req_complete;
-+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
-+
-+#define EVT_ENCRYPT_CHANGE 0x08
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 encrypt;
-+} __attribute__ ((packed)) evt_encrypt_change;
-+#define EVT_ENCRYPT_CHANGE_SIZE 5
-+
-+#define EVT_QOS_SETUP_COMPLETE 0x0D
-+typedef struct {
-+ __u8 service_type;
-+ __u32 token_rate;
-+ __u32 peak_bandwidth;
-+ __u32 latency;
-+ __u32 delay_variation;
-+} __attribute__ ((packed)) hci_qos;
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ hci_qos qos;
-+} __attribute__ ((packed)) evt_qos_setup_complete;
-+#define EVT_QOS_SETUP_COMPLETE_SIZE 20
-+
- #define EVT_CMD_COMPLETE 0x0e
- typedef struct {
- __u8 ncmd;
-@@ -321,16 +560,78 @@
- #define EVT_NUM_COMP_PKTS 0x13
- typedef struct {
- __u8 num_hndl;
-- /* variable lenght part */
-+ /* variable length part */
- } __attribute__ ((packed)) evt_num_comp_pkts;
- #define EVT_NUM_COMP_PKTS_SIZE 1
-
--#define EVT_HCI_DEV_EVENT 0xfd
-+#define EVT_ROLE_CHANGE 0x12
-+typedef struct {
-+ __u8 status;
-+ bdaddr_t bdaddr;
-+ __u8 role;
-+} __attribute__ ((packed)) evt_role_change;
-+#define EVT_ROLE_CHANGE_SIZE 8
-+
-+#define EVT_PIN_CODE_REQ 0x16
-+typedef struct {
-+ bdaddr_t bdaddr;
-+} __attribute__ ((packed)) evt_pin_code_req;
-+#define EVT_PIN_CODE_REQ_SIZE 6
-+
-+#define EVT_LINK_KEY_REQ 0x17
-+typedef struct {
-+ bdaddr_t bdaddr;
-+} __attribute__ ((packed)) evt_link_key_req;
-+#define EVT_LINK_KEY_REQ_SIZE 6
-+
-+#define EVT_LINK_KEY_NOTIFY 0x18
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 link_key[16];
-+ __u8 key_type;
-+} __attribute__ ((packed)) evt_link_key_notify;
-+#define EVT_LINK_KEY_NOTIFY_SIZE 23
-+
-+#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 features[8];
-+} __attribute__ ((packed)) evt_read_remote_features_complete;
-+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
-+
-+#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 lmp_ver;
-+ __u16 manufacturer;
-+ __u16 lmp_subver;
-+} __attribute__ ((packed)) evt_read_remote_version_complete;
-+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
-+
-+/* Internal events generated by BlueZ stack */
-+#define EVT_STACK_INTERNAL 0xfd
-+typedef struct {
-+ __u16 type;
-+ __u8 data[0];
-+} __attribute__ ((packed)) evt_stack_internal;
-+#define EVT_STACK_INTERNAL_SIZE 2
-+
-+#define EVT_SI_DEVICE 0x01
-+typedef struct {
-+ __u16 event;
-+ __u16 dev_id;
-+} __attribute__ ((packed)) evt_si_device;
-+#define EVT_SI_DEVICE_SIZE 4
-+
-+#define EVT_SI_SECURITY 0x02
- typedef struct {
- __u16 event;
-- __u16 param;
--} __attribute__ ((packed)) evt_hci_dev_event;
--#define EVT_HCI_DEV_EVENT_SIZE 4
-+ __u16 proto;
-+ __u16 subproto;
-+ __u8 incomming;
-+} __attribute__ ((packed)) evt_si_security;
-
- /* -------- HCI Packet structures -------- */
- #define HCI_TYPE_LEN 1
-@@ -369,14 +670,14 @@
- #define acl_handle(h) (h & 0x0fff)
- #define acl_flags(h) (h >> 12)
-
--#endif /* _NO_HCI_DEFS */
--
- /* HCI Socket options */
--#define HCI_DATA_DIR 0x0001
--#define HCI_FILTER 0x0002
-+#define HCI_DATA_DIR 1
-+#define HCI_FILTER 2
-+#define HCI_TIME_STAMP 3
-
- /* HCI CMSG flags */
- #define HCI_CMSG_DIR 0x0001
-+#define HCI_CMSG_TSTAMP 0x0002
-
- struct sockaddr_hci {
- sa_family_t hci_family;
-@@ -387,27 +688,29 @@
- struct hci_filter {
- __u32 type_mask;
- __u32 event_mask[2];
-+ __u16 opcode;
- };
-
--struct hci_dev_req {
-- __u16 dev_id;
-- __u32 dev_opt;
--};
--
--struct hci_dev_list_req {
-- __u16 dev_num;
-- struct hci_dev_req dev_req[0]; /* hci_dev_req structures */
--};
--
--struct hci_inquiry_req {
-- __u16 dev_id;
-- __u16 flags;
-- __u8 lap[3];
-- __u8 length;
-- __u8 num_rsp;
--};
--#define IREQ_CACHE_FLUSH 0x0001
-+#define HCI_FLT_TYPE_BITS 31
-+#define HCI_FLT_EVENT_BITS 63
-+#define HCI_FLT_OGF_BITS 63
-+#define HCI_FLT_OCF_BITS 127
-+
-+#if BITS_PER_LONG == 64
-+static inline void hci_set_bit(int nr, void *addr)
-+{
-+ *((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
-+}
-+static inline int hci_test_bit(int nr, void *addr)
-+{
-+ return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
-+}
-+#else
-+#define hci_set_bit set_bit
-+#define hci_test_bit test_bit
-+#endif
-
-+/* Ioctl requests structures */
- struct hci_dev_stats {
- __u32 err_rx;
- __u32 err_tx;
-@@ -433,11 +736,13 @@
- __u8 features[8];
-
- __u32 pkt_type;
-+ __u32 link_policy;
-+ __u32 link_mode;
-
- __u16 acl_mtu;
-- __u16 acl_max;
-+ __u16 acl_pkts;
- __u16 sco_mtu;
-- __u16 sco_max;
-+ __u16 sco_pkts;
-
- struct hci_dev_stats stat;
- };
-@@ -445,6 +750,20 @@
- struct hci_conn_info {
- __u16 handle;
- bdaddr_t bdaddr;
-+ __u8 type;
-+ __u8 out;
-+ __u16 state;
-+ __u32 link_mode;
-+};
-+
-+struct hci_dev_req {
-+ __u16 dev_id;
-+ __u32 dev_opt;
-+};
-+
-+struct hci_dev_list_req {
-+ __u16 dev_num;
-+ struct hci_dev_req dev_req[0]; /* hci_dev_req structures */
- };
-
- struct hci_conn_list_req {
-@@ -453,4 +772,26 @@
- struct hci_conn_info conn_info[0];
- };
-
-+struct hci_conn_info_req {
-+ bdaddr_t bdaddr;
-+ __u8 type;
-+ struct hci_conn_info conn_info[0];
-+};
-+
-+struct hci_inquiry_req {
-+ __u16 dev_id;
-+ __u16 flags;
-+ __u8 lap[3];
-+ __u8 length;
-+ __u8 num_rsp;
-+};
-+#define IREQ_CACHE_FLUSH 0x0001
-+
-+struct hci_remotename_req {
-+ __u16 dev_id;
-+ __u16 flags;
-+ bdaddr_t bdaddr;
-+ __u8 name[248];
-+};
-+
- #endif /* __HCI_H */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_uart.h linux-2.4.18-mh15/include/net/bluetooth/hci_uart.h
---- linux-2.4.18/include/net/bluetooth/hci_uart.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/hci_uart.h 1970-01-01 01:00:00.000000000 +0100
-@@ -1,62 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef N_HCI
--#define N_HCI 15
--#endif
--
--#ifdef __KERNEL__
--
--#define tty2n_hci(tty) ((struct n_hci *)((tty)->disc_data))
--#define n_hci2tty(n_hci) ((n_hci)->tty)
--
--struct n_hci {
-- struct tty_struct *tty;
-- struct hci_dev hdev;
--
-- struct sk_buff_head txq;
-- unsigned long tx_state;
--
-- spinlock_t rx_lock;
-- unsigned long rx_state;
-- unsigned long rx_count;
-- struct sk_buff *rx_skb;
--};
--
--/* Transmit states */
--#define TRANS_SENDING 1
--#define TRANS_WAKEUP 2
--
--/* Receiver States */
--#define WAIT_PACKET_TYPE 0
--#define WAIT_EVENT_HDR 1
--#define WAIT_ACL_HDR 2
--#define WAIT_SCO_HDR 3
--#define WAIT_DATA 4
--
--#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_usb.h linux-2.4.18-mh15/include/net/bluetooth/hci_usb.h
---- linux-2.4.18/include/net/bluetooth/hci_usb.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/hci_usb.h 1970-01-01 01:00:00.000000000 +0100
-@@ -1,68 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifdef __KERNEL__
--
--/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
--#define HCI_DEV_CLASS 0xe0 /* Wireless class */
--#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */
--#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */
--
--#define HCI_CTRL_REQ 0x20
--
--struct hci_usb {
-- struct usb_device *udev;
--
-- devrequest dev_req;
-- struct urb *ctrl_urb;
-- struct urb *intr_urb;
-- struct urb *read_urb;
-- struct urb *write_urb;
--
-- __u8 *read_buf;
-- __u8 *intr_buf;
-- struct sk_buff *intr_skb;
-- int intr_count;
--
-- __u8 bulk_out_ep_addr;
-- __u8 bulk_in_ep_addr;
-- __u8 intr_in_ep_addr;
-- __u8 intr_in_interval;
--
-- struct hci_dev hdev;
--
-- unsigned long tx_state;
-- struct sk_buff_head tx_ctrl_q;
-- struct sk_buff_head tx_write_q;
--};
--
--/* Transmit states */
--#define HCI_TX_CTRL 1
--#define HCI_TX_WRITE 2
--
--#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_vhci.h linux-2.4.18-mh15/include/net/bluetooth/hci_vhci.h
---- linux-2.4.18/include/net/bluetooth/hci_vhci.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/hci_vhci.h 1970-01-01 01:00:00.000000000 +0100
-@@ -1,50 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef __HCI_VHCI_H
--#define __HCI_VHCI_H
--
--#ifdef __KERNEL__
--
--struct hci_vhci_struct {
-- struct hci_dev hdev;
-- __u32 flags;
-- wait_queue_head_t read_wait;
-- struct sk_buff_head readq;
-- struct fasync_struct *fasync;
--};
--
--/* VHCI device flags */
--#define VHCI_FASYNC 0x0010
--
--#endif /* __KERNEL__ */
--
--#define VHCI_DEV "/dev/vhci"
--#define VHCI_MINOR 250
--
--#endif /* __HCI_VHCI_H */
-diff -urN linux-2.4.18/include/net/bluetooth/l2cap_core.h linux-2.4.18-mh15/include/net/bluetooth/l2cap_core.h
---- linux-2.4.18/include/net/bluetooth/l2cap_core.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/l2cap_core.h 1970-01-01 01:00:00.000000000 +0100
-@@ -1,144 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef __L2CAP_CORE_H
--#define __L2CAP_CORE_H
--
--#ifdef __KERNEL__
--
--/* ----- L2CAP interface ----- */
--struct l2cap_iff {
-- struct list_head list;
-- struct hci_dev *hdev;
-- bdaddr_t *bdaddr;
-- __u16 mtu;
-- spinlock_t lock;
-- struct list_head conn_list;
--};
--
--static inline void l2cap_iff_lock(struct l2cap_iff *iff)
--{
-- spin_lock(&iff->lock);
--}
--
--static inline void l2cap_iff_unlock(struct l2cap_iff *iff)
--{
-- spin_unlock(&iff->lock);
--}
--
--/* ----- L2CAP connections ----- */
--struct l2cap_chan_list {
-- struct sock *head;
-- rwlock_t lock;
-- long num;
--};
--
--struct l2cap_conn {
-- struct l2cap_iff *iff;
-- struct list_head list;
--
-- struct hci_conn *hconn;
--
-- __u16 state;
-- __u8 out;
-- bdaddr_t src;
-- bdaddr_t dst;
--
-- spinlock_t lock;
-- atomic_t refcnt;
--
-- struct sk_buff *rx_skb;
-- __u32 rx_len;
-- __u8 rx_ident;
-- __u8 tx_ident;
--
-- struct l2cap_chan_list chan_list;
--
-- struct timer_list timer;
--};
--
--static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
--{
-- list_add(&c->list, &iff->conn_list);
--}
--
--static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
--{
-- list_del(&c->list);
--}
--
--/* ----- L2CAP channel and socket info ----- */
--#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->protinfo)
--
--struct l2cap_accept_q {
-- struct sock *head;
-- struct sock *tail;
--};
--
--struct l2cap_pinfo {
-- bdaddr_t src;
-- bdaddr_t dst;
-- __u16 psm;
-- __u16 dcid;
-- __u16 scid;
-- __u32 flags;
--
-- __u16 imtu;
-- __u16 omtu;
-- __u16 flush_to;
--
-- __u8 conf_state;
-- __u16 conf_mtu;
--
-- __u8 ident;
--
-- struct l2cap_conn *conn;
-- struct sock *next_c;
-- struct sock *prev_c;
--
-- struct sock *parent;
-- struct sock *next_q;
-- struct sock *prev_q;
--
-- struct l2cap_accept_q accept_q;
--};
--
--#define CONF_REQ_SENT 0x01
--#define CONF_INPUT_DONE 0x02
--#define CONF_OUTPUT_DONE 0x04
--
--extern struct bluez_sock_list l2cap_sk_list;
--extern struct list_head l2cap_iff_list;
--extern rwlock_t l2cap_rt_lock;
--
--extern void l2cap_register_proc(void);
--extern void l2cap_unregister_proc(void);
--
--#endif /* __KERNEL__ */
--
--#endif /* __L2CAP_CORE_H */
-diff -urN linux-2.4.18/include/net/bluetooth/l2cap.h linux-2.4.18-mh15/include/net/bluetooth/l2cap.h
---- linux-2.4.18/include/net/bluetooth/l2cap.h 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/include/net/bluetooth/l2cap.h 2004-08-01 16:26:23.000000000 +0200
-@@ -23,22 +23,17 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __L2CAP_H
- #define __L2CAP_H
-
--#include <asm/types.h>
--#include <asm/byteorder.h>
--
- /* L2CAP defaults */
- #define L2CAP_DEFAULT_MTU 672
- #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
-
- #define L2CAP_CONN_TIMEOUT (HZ * 40)
--#define L2CAP_DISCONN_TIMEOUT (HZ * 2)
--#define L2CAP_CONN_IDLE_TIMEOUT (HZ * 60)
-
- /* L2CAP socket address */
- struct sockaddr_l2 {
-@@ -47,17 +42,12 @@
- bdaddr_t l2_bdaddr;
- };
-
--/* set/get sockopt defines */
--#define L2CAP_OPTIONS 0x01
-+/* Socket options */
-+#define L2CAP_OPTIONS 0x01
- struct l2cap_options {
- __u16 omtu;
- __u16 imtu;
- __u16 flush_to;
-- __u32 token_rate;
-- __u32 bucket_size;
-- __u32 pick_band;
-- __u32 latency;
-- __u32 delay_var;
- };
-
- #define L2CAP_CONNINFO 0x02
-@@ -65,6 +55,27 @@
- __u16 hci_handle;
- };
-
-+#define L2CAP_LM 0x03
-+#define L2CAP_LM_MASTER 0x0001
-+#define L2CAP_LM_AUTH 0x0002
-+#define L2CAP_LM_ENCRYPT 0x0004
-+#define L2CAP_LM_TRUSTED 0x0008
-+#define L2CAP_LM_RELIABLE 0x0010
-+
-+#define L2CAP_QOS 0x04
-+struct l2cap_qos {
-+ __u16 service_type;
-+ __u32 token_rate;
-+ __u32 token_bucket_size;
-+ __u32 peak_bandwidth;
-+ __u32 latency;
-+ __u32 delay_variation;
-+};
-+
-+#define L2CAP_SERV_NO_TRAFFIC 0x00
-+#define L2CAP_SERV_BEST_EFFORT 0x01
-+#define L2CAP_SERV_GUARANTEED 0x02
-+
- /* L2CAP command codes */
- #define L2CAP_COMMAND_REJ 0x01
- #define L2CAP_CONN_REQ 0x02
-@@ -79,7 +90,6 @@
- #define L2CAP_INFO_RSP 0x0b
-
- /* L2CAP structures */
--
- typedef struct {
- __u16 len;
- __u16 cid;
-@@ -112,11 +122,17 @@
- } __attribute__ ((packed)) l2cap_conn_rsp;
- #define L2CAP_CONN_RSP_SIZE 8
-
--#define L2CAP_CONN_SUCCESS 0x0000
--#define L2CAP_CONN_PEND 0x0001
--#define L2CAP_CONN_BAD_PSM 0x0002
--#define L2CAP_CONN_SEC_BLOCK 0x0003
--#define L2CAP_CONN_NO_MEM 0x0004
-+/* connect result */
-+#define L2CAP_CR_SUCCESS 0x0000
-+#define L2CAP_CR_PEND 0x0001
-+#define L2CAP_CR_BAD_PSM 0x0002
-+#define L2CAP_CR_SEC_BLOCK 0x0003
-+#define L2CAP_CR_NO_MEM 0x0004
-+
-+/* connect status */
-+#define L2CAP_CS_NO_INFO 0x0000
-+#define L2CAP_CS_AUTHEN_PEND 0x0001
-+#define L2CAP_CS_AUTHOR_PEND 0x0002
-
- typedef struct {
- __u16 dcid;
-@@ -147,6 +163,8 @@
- #define L2CAP_CONF_FLUSH_TO 0x02
- #define L2CAP_CONF_QOS 0x03
-
-+#define L2CAP_CONF_MAX_SIZE 22
-+
- typedef struct {
- __u16 dcid;
- __u16 scid;
-@@ -159,4 +177,82 @@
- } __attribute__ ((packed)) l2cap_disconn_rsp;
- #define L2CAP_DISCONN_RSP_SIZE 4
-
-+typedef struct {
-+ __u16 type;
-+ __u8 data[0];
-+} __attribute__ ((packed)) l2cap_info_req;
-+#define L2CAP_INFO_REQ_SIZE 2
-+
-+typedef struct {
-+ __u16 type;
-+ __u16 result;
-+ __u8 data[0];
-+} __attribute__ ((packed)) l2cap_info_rsp;
-+#define L2CAP_INFO_RSP_SIZE 4
-+
-+/* info type */
-+#define L2CAP_IT_CL_MTU 0x0001
-+#define L2CAP_IT_FEAT_MASK 0x0002
-+
-+/* info result */
-+#define L2CAP_IR_SUCCESS 0x0000
-+#define L2CAP_IR_NOTSUPP 0x0001
-+
-+/* ----- L2CAP connections ----- */
-+struct l2cap_chan_list {
-+ struct sock *head;
-+ rwlock_t lock;
-+ long num;
-+};
-+
-+struct l2cap_conn {
-+ struct hci_conn *hcon;
-+
-+ bdaddr_t *dst;
-+ bdaddr_t *src;
-+
-+ unsigned int mtu;
-+
-+ spinlock_t lock;
-+
-+ struct sk_buff *rx_skb;
-+ __u32 rx_len;
-+ __u8 rx_ident;
-+ __u8 tx_ident;
-+
-+ struct l2cap_chan_list chan_list;
-+};
-+
-+/* ----- L2CAP channel and socket info ----- */
-+#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->tp_pinfo)
-+
-+struct l2cap_pinfo {
-+ __u16 psm;
-+ __u16 dcid;
-+ __u16 scid;
-+
-+ __u16 imtu;
-+ __u16 omtu;
-+ __u16 flush_to;
-+
-+ __u32 link_mode;
-+
-+ __u8 conf_state;
-+ __u8 conf_retry;
-+ __u16 conf_mtu;
-+
-+ __u8 ident;
-+
-+ struct l2cap_conn *conn;
-+ struct sock *next_c;
-+ struct sock *prev_c;
-+};
-+
-+#define L2CAP_CONF_REQ_SENT 0x01
-+#define L2CAP_CONF_INPUT_DONE 0x02
-+#define L2CAP_CONF_OUTPUT_DONE 0x04
-+#define L2CAP_CONF_MAX_RETRIES 2
-+
-+void l2cap_load(void);
-+
- #endif /* __L2CAP_H */
-diff -urN linux-2.4.18/include/net/bluetooth/rfcomm.h linux-2.4.18-mh15/include/net/bluetooth/rfcomm.h
---- linux-2.4.18/include/net/bluetooth/rfcomm.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/include/net/bluetooth/rfcomm.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,361 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ RPN support - Dirk Husemann <hud@zurich.ibm.com>
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __RFCOMM_H
-+#define __RFCOMM_H
-+
-+#define RFCOMM_PSM 3
-+
-+#define RFCOMM_CONN_TIMEOUT (HZ * 30)
-+#define RFCOMM_DISC_TIMEOUT (HZ * 20)
-+
-+#define RFCOMM_DEFAULT_MTU 127
-+#define RFCOMM_DEFAULT_CREDITS 7
-+
-+#define RFCOMM_MAX_L2CAP_MTU 1024
-+#define RFCOMM_MAX_CREDITS 40
-+
-+#define RFCOMM_SKB_HEAD_RESERVE 8
-+#define RFCOMM_SKB_TAIL_RESERVE 2
-+#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
-+
-+#define RFCOMM_SABM 0x2f
-+#define RFCOMM_DISC 0x43
-+#define RFCOMM_UA 0x63
-+#define RFCOMM_DM 0x0f
-+#define RFCOMM_UIH 0xef
-+
-+#define RFCOMM_TEST 0x08
-+#define RFCOMM_FCON 0x28
-+#define RFCOMM_FCOFF 0x18
-+#define RFCOMM_MSC 0x38
-+#define RFCOMM_RPN 0x24
-+#define RFCOMM_RLS 0x14
-+#define RFCOMM_PN 0x20
-+#define RFCOMM_NSC 0x04
-+
-+#define RFCOMM_V24_FC 0x02
-+#define RFCOMM_V24_RTC 0x04
-+#define RFCOMM_V24_RTR 0x08
-+#define RFCOMM_V24_IC 0x40
-+#define RFCOMM_V24_DV 0x80
-+
-+#define RFCOMM_RPN_BR_2400 0x0
-+#define RFCOMM_RPN_BR_4800 0x1
-+#define RFCOMM_RPN_BR_7200 0x2
-+#define RFCOMM_RPN_BR_9600 0x3
-+#define RFCOMM_RPN_BR_19200 0x4
-+#define RFCOMM_RPN_BR_38400 0x5
-+#define RFCOMM_RPN_BR_57600 0x6
-+#define RFCOMM_RPN_BR_115200 0x7
-+#define RFCOMM_RPN_BR_230400 0x8
-+
-+#define RFCOMM_RPN_DATA_5 0x0
-+#define RFCOMM_RPN_DATA_6 0x1
-+#define RFCOMM_RPN_DATA_7 0x2
-+#define RFCOMM_RPN_DATA_8 0x3
-+
-+#define RFCOMM_RPN_STOP_1 0
-+#define RFCOMM_RPN_STOP_15 1
-+
-+#define RFCOMM_RPN_PARITY_NONE 0x0
-+#define RFCOMM_RPN_PARITY_ODD 0x4
-+#define RFCOMM_RPN_PARITY_EVEN 0x5
-+#define RFCOMM_RPN_PARITY_MARK 0x6
-+#define RFCOMM_RPN_PARITY_SPACE 0x7
-+
-+#define RFCOMM_RPN_FLOW_NONE 0x00
-+
-+#define RFCOMM_RPN_XON_CHAR 0x11
-+#define RFCOMM_RPN_XOFF_CHAR 0x13
-+
-+#define RFCOMM_RPN_PM_BITRATE 0x0001
-+#define RFCOMM_RPN_PM_DATA 0x0002
-+#define RFCOMM_RPN_PM_STOP 0x0004
-+#define RFCOMM_RPN_PM_PARITY 0x0008
-+#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010
-+#define RFCOMM_RPN_PM_XON 0x0020
-+#define RFCOMM_RPN_PM_XOFF 0x0040
-+#define RFCOMM_RPN_PM_FLOW 0x3F00
-+
-+#define RFCOMM_RPN_PM_ALL 0x3F7F
-+
-+struct rfcomm_hdr {
-+ u8 addr;
-+ u8 ctrl;
-+ u8 len; // Actual size can be 2 bytes
-+} __attribute__ ((packed));
-+
-+struct rfcomm_cmd {
-+ u8 addr;
-+ u8 ctrl;
-+ u8 len;
-+ u8 fcs;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_mcc {
-+ u8 type;
-+ u8 len;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_pn {
-+ u8 dlci;
-+ u8 flow_ctrl;
-+ u8 priority;
-+ u8 ack_timer;
-+ u16 mtu;
-+ u8 max_retrans;
-+ u8 credits;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_rpn {
-+ u8 dlci;
-+ u8 bit_rate;
-+ u8 line_settings;
-+ u8 flow_ctrl;
-+ u8 xon_char;
-+ u8 xoff_char;
-+ u16 param_mask;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_rls {
-+ u8 dlci;
-+ u8 status;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_msc {
-+ u8 dlci;
-+ u8 v24_sig;
-+} __attribute__ ((packed));
-+
-+/* ---- Core structures, flags etc ---- */
-+
-+struct rfcomm_session {
-+ struct list_head list;
-+ struct socket *sock;
-+ unsigned long state;
-+ unsigned long flags;
-+ atomic_t refcnt;
-+ int initiator;
-+
-+ /* Default DLC parameters */
-+ int cfc;
-+ uint mtu;
-+
-+ struct list_head dlcs;
-+};
-+
-+struct rfcomm_dlc {
-+ struct list_head list;
-+ struct rfcomm_session *session;
-+ struct sk_buff_head tx_queue;
-+ struct timer_list timer;
-+
-+ spinlock_t lock;
-+ unsigned long state;
-+ unsigned long flags;
-+ atomic_t refcnt;
-+ u8 dlci;
-+ u8 addr;
-+ u8 priority;
-+ u8 v24_sig;
-+ u8 mscex;
-+
-+ uint mtu;
-+ uint cfc;
-+ uint rx_credits;
-+ uint tx_credits;
-+
-+ void *owner;
-+
-+ void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
-+ void (*state_change)(struct rfcomm_dlc *d, int err);
-+ void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
-+};
-+
-+/* DLC and session flags */
-+#define RFCOMM_RX_THROTTLED 0
-+#define RFCOMM_TX_THROTTLED 1
-+#define RFCOMM_MSC_PENDING 2
-+#define RFCOMM_TIMED_OUT 3
-+
-+/* Scheduling flags and events */
-+#define RFCOMM_SCHED_STATE 0
-+#define RFCOMM_SCHED_RX 1
-+#define RFCOMM_SCHED_TX 2
-+#define RFCOMM_SCHED_TIMEO 3
-+#define RFCOMM_SCHED_WAKEUP 31
-+
-+/* MSC exchange flags */
-+#define RFCOMM_MSCEX_TX 1
-+#define RFCOMM_MSCEX_RX 2
-+#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
-+
-+/* CFC states */
-+#define RFCOMM_CFC_UNKNOWN -1
-+#define RFCOMM_CFC_DISABLED 0
-+#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS
-+
-+extern struct task_struct *rfcomm_thread;
-+extern unsigned long rfcomm_event;
-+
-+static inline void rfcomm_schedule(uint event)
-+{
-+ if (!rfcomm_thread)
-+ return;
-+ set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-+ wake_up_process(rfcomm_thread);
-+}
-+
-+extern struct semaphore rfcomm_sem;
-+#define rfcomm_lock() down(&rfcomm_sem);
-+#define rfcomm_unlock() up(&rfcomm_sem);
-+
-+/* ---- RFCOMM DLCs (channels) ---- */
-+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
-+void rfcomm_dlc_free(struct rfcomm_dlc *d);
-+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
-+int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
-+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
-+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
-+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
-+
-+#define rfcomm_dlc_lock(d) spin_lock(&d->lock)
-+#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock)
-+
-+static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
-+{
-+ atomic_inc(&d->refcnt);
-+}
-+
-+static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
-+{
-+ if (atomic_dec_and_test(&d->refcnt))
-+ rfcomm_dlc_free(d);
-+}
-+
-+extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
-+extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
-+
-+static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-+{
-+ if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+ __rfcomm_dlc_throttle(d);
-+}
-+
-+static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-+{
-+ if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+ __rfcomm_dlc_unthrottle(d);
-+}
-+
-+/* ---- RFCOMM sessions ---- */
-+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
-+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
-+void rfcomm_session_del(struct rfcomm_session *s);
-+void rfcomm_session_close(struct rfcomm_session *s, int err);
-+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
-+
-+static inline void rfcomm_session_hold(struct rfcomm_session *s)
-+{
-+ atomic_inc(&s->refcnt);
-+}
-+
-+static inline void rfcomm_session_put(struct rfcomm_session *s)
-+{
-+ if (atomic_dec_and_test(&s->refcnt))
-+ rfcomm_session_del(s);
-+}
-+
-+/* ---- RFCOMM chechsum ---- */
-+extern u8 rfcomm_crc_table[];
-+
-+/* ---- RFCOMM sockets ---- */
-+struct sockaddr_rc {
-+ sa_family_t rc_family;
-+ bdaddr_t rc_bdaddr;
-+ u8 rc_channel;
-+};
-+
-+#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->tp_pinfo)
-+
-+struct rfcomm_pinfo {
-+ struct rfcomm_dlc *dlc;
-+ u8 channel;
-+};
-+
-+int rfcomm_init_sockets(void);
-+void rfcomm_cleanup_sockets(void);
-+
-+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
-+
-+/* ---- RFCOMM TTY ---- */
-+#define RFCOMM_MAX_DEV 256
-+
-+#define RFCOMMCREATEDEV _IOW('R', 200, int)
-+#define RFCOMMRELEASEDEV _IOW('R', 201, int)
-+#define RFCOMMGETDEVLIST _IOR('R', 210, int)
-+#define RFCOMMGETDEVINFO _IOR('R', 211, int)
-+#define RFCOMMSTEALDLC _IOW('R', 220, int)
-+
-+#define RFCOMM_REUSE_DLC 0
-+#define RFCOMM_RELEASE_ONHUP 1
-+#define RFCOMM_HANGUP_NOW 2
-+#define RFCOMM_TTY_ATTACHED 3
-+
-+struct rfcomm_dev_req {
-+ s16 dev_id;
-+ u32 flags;
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+ u8 channel;
-+};
-+
-+struct rfcomm_dev_info {
-+ s16 id;
-+ u32 flags;
-+ u16 state;
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+ u8 channel;
-+};
-+
-+struct rfcomm_dev_list_req {
-+ u16 dev_num;
-+ struct rfcomm_dev_info dev_info[0];
-+};
-+
-+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
-+int rfcomm_init_ttys(void);
-+void rfcomm_cleanup_ttys(void);
-+
-+#endif /* __RFCOMM_H */
-diff -urN linux-2.4.18/include/net/bluetooth/sco.h linux-2.4.18-mh15/include/net/bluetooth/sco.h
---- linux-2.4.18/include/net/bluetooth/sco.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/include/net/bluetooth/sco.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,81 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __SCO_H
-+#define __SCO_H
-+
-+/* SCO defaults */
-+#define SCO_DEFAULT_MTU 500
-+#define SCO_DEFAULT_FLUSH_TO 0xFFFF
-+
-+#define SCO_CONN_TIMEOUT (HZ * 40)
-+#define SCO_DISCONN_TIMEOUT (HZ * 2)
-+#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
-+
-+/* SCO socket address */
-+struct sockaddr_sco {
-+ sa_family_t sco_family;
-+ bdaddr_t sco_bdaddr;
-+};
-+
-+/* set/get sockopt defines */
-+#define SCO_OPTIONS 0x01
-+struct sco_options {
-+ __u16 mtu;
-+};
-+
-+#define SCO_CONNINFO 0x02
-+struct sco_conninfo {
-+ __u16 hci_handle;
-+};
-+
-+/* ---- SCO connections ---- */
-+struct sco_conn {
-+ struct hci_conn *hcon;
-+
-+ bdaddr_t *dst;
-+ bdaddr_t *src;
-+
-+ spinlock_t lock;
-+ struct sock *sk;
-+
-+ unsigned int mtu;
-+};
-+
-+#define sco_conn_lock(c) spin_lock(&c->lock);
-+#define sco_conn_unlock(c) spin_unlock(&c->lock);
-+
-+/* ----- SCO socket info ----- */
-+#define sco_pi(sk) ((struct sco_pinfo *) &sk->tp_pinfo)
-+
-+struct sco_pinfo {
-+ __u32 flags;
-+ struct sco_conn *conn;
-+};
-+
-+#endif /* __SCO_H */
-diff -urN linux-2.4.18/include/pcmcia/ciscode.h linux-2.4.18-mh15/include/pcmcia/ciscode.h
---- linux-2.4.18/include/pcmcia/ciscode.h 2001-12-21 18:42:04.000000000 +0100
-+++ linux-2.4.18-mh15/include/pcmcia/ciscode.h 2004-08-01 16:26:23.000000000 +0200
-@@ -1,5 +1,5 @@
- /*
-- * ciscode.h 1.48 2001/08/24 12:16:12
-+ * ciscode.h 1.57 2002/11/03 20:38:14
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
-@@ -60,6 +60,10 @@
- #define PRODID_INTEL_DUAL_RS232 0x0301
- #define PRODID_INTEL_2PLUS 0x8422
-
-+#define MANFID_KME 0x0032
-+#define PRODID_KME_KXLC005_A 0x0704
-+#define PRODID_KME_KXLC005_B 0x2904
-+
- #define MANFID_LINKSYS 0x0143
- #define PRODID_LINKSYS_PCMLM28 0xc0ab
- #define PRODID_LINKSYS_3400 0x3341
-@@ -94,6 +98,8 @@
- #define PRODID_OSITECH_JACK_336 0x0007
- #define PRODID_OSITECH_SEVEN 0x0008
-
-+#define MANFID_OXSEMI 0x0279
-+
- #define MANFID_PIONEER 0x000b
-
- #define MANFID_PSION 0x016c
-@@ -103,6 +109,7 @@
- #define PRODID_QUATECH_SPP100 0x0003
- #define PRODID_QUATECH_DUAL_RS232 0x0012
- #define PRODID_QUATECH_DUAL_RS232_D1 0x0007
-+#define PRODID_QUATECH_DUAL_RS232_D2 0x0052
- #define PRODID_QUATECH_QUAD_RS232 0x001b
- #define PRODID_QUATECH_DUAL_RS422 0x000e
- #define PRODID_QUATECH_QUAD_RS422 0x0045
-@@ -120,9 +127,12 @@
-
- #define MANFID_TDK 0x0105
- #define PRODID_TDK_CF010 0x0900
-+#define PRODID_TDK_GN3410 0x4815
-
- #define MANFID_TOSHIBA 0x0098
-
-+#define MANFID_UNGERMANN 0x02c0
-+
- #define MANFID_XIRCOM 0x0105
-
- #endif /* _LINUX_CISCODE_H */
-diff -urN linux-2.4.18/kernel/ksyms.c linux-2.4.18-mh15/kernel/ksyms.c
---- linux-2.4.18/kernel/ksyms.c 2002-02-25 20:38:13.000000000 +0100
-+++ linux-2.4.18-mh15/kernel/ksyms.c 2004-08-01 16:26:23.000000000 +0200
-@@ -47,6 +47,7 @@
- #include <linux/in6.h>
- #include <linux/completion.h>
- #include <linux/seq_file.h>
-+#include <linux/firmware.h>
- #include <asm/checksum.h>
-
- #if defined(CONFIG_PROC_FS)
-@@ -538,6 +539,13 @@
- EXPORT_SYMBOL(strspn);
- EXPORT_SYMBOL(strsep);
-
-+#ifdef CONFIG_FW_LOADER
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-+#endif
-+
- /* software interrupts */
- EXPORT_SYMBOL(tasklet_hi_vec);
- EXPORT_SYMBOL(tasklet_vec);
-diff -urN linux-2.4.18/lib/Config.in linux-2.4.18-mh15/lib/Config.in
---- linux-2.4.18/lib/Config.in 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/lib/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,12 @@
-+#
-+# Library configuration
-+#
-+mainmenu_option next_comment
-+comment 'Library routines'
-+
-+if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
-+ "$CONFIG_HOTPLUG" = "y" ]; then
-+ tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER
-+fi
-+
-+endmenu
-diff -urN linux-2.4.18/lib/firmware_class.c linux-2.4.18-mh15/lib/firmware_class.c
---- linux-2.4.18/lib/firmware_class.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/lib/firmware_class.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,573 @@
-+/*
-+ * firmware_class.c - Multi purpose firmware loading support
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Please see Documentation/firmware_class/ for more information.
-+ *
-+ */
-+/*
-+ * Based on kernel/kmod.c and drivers/usb/usb.c
-+ */
-+/*
-+ kernel/kmod.c
-+ Kirk Petersen
-+
-+ Reorganized not to be a daemon by Adam Richter, with guidance
-+ from Greg Zornetzer.
-+
-+ Modified to avoid chroot and file sharing problems.
-+ Mikael Pettersson
-+
-+ Limit the concurrent number of kmod modprobes to catch loops from
-+ "modprobe needs a service that is in a module".
-+ Keith Owens <kaos@ocs.com.au> December 1999
-+
-+ Unblock all signals when we exec a usermode process.
-+ Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
-+*/
-+/*
-+ * drivers/usb/usb.c
-+ *
-+ * (C) Copyright Linus Torvalds 1999
-+ * (C) Copyright Johannes Erdfelt 1999-2001
-+ * (C) Copyright Andreas Gal 1999
-+ * (C) Copyright Gregory P. Smith 1999
-+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
-+ * (C) Copyright Randy Dunlap 2000
-+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
-+ * (C) Copyright Yggdrasil Computing, Inc. 2000
-+ * (usb_device_id matching changes by Adam J. Richter)
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/kmod.h>
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+#include <asm/hardirq.h>
-+
-+#include "linux/firmware.h"
-+
-+MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
-+MODULE_DESCRIPTION("Multi purpose firmware loading support");
-+MODULE_LICENSE("GPL");
-+
-+#define err(format, arg...) \
-+ printk(KERN_ERR "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define warn(format, arg...) \
-+ printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define dbg(format, arg...) \
-+ printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+
-+static int loading_timeout = 10; /* In seconds */
-+static struct proc_dir_entry *proc_dir_timeout;
-+static struct proc_dir_entry *proc_dir;
-+
-+#ifdef CONFIG_HOTPLUG
-+
-+static int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+ char *argv[3], **envp, *buf, *scratch;
-+ int i = 0;
-+
-+ int retval = 0;
-+
-+ if (!hotplug_path[0])
-+ return -ENOENT;
-+ if (in_interrupt()) {
-+ err("in_interrupt");
-+ return -EFAULT;
-+ }
-+ if (!current->fs->root) {
-+ warn("call_policy %s -- no FS yet", verb);
-+ return -EPERM;
-+ }
-+
-+ if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
-+ err("unable to allocate envp");
-+ return -ENOMEM;
-+ }
-+ if (!(buf = kmalloc(256, GFP_KERNEL))) {
-+ kfree(envp);
-+ err("unable to allocate buf");
-+ return -ENOMEM;
-+ }
-+
-+ /* only one standardized param to hotplug command: type */
-+ argv[0] = hotplug_path;
-+ argv[1] = "firmware";
-+ argv[2] = 0;
-+
-+ /* minimal command environment */
-+ envp[i++] = "HOME=/";
-+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+
-+#ifdef DEBUG
-+ /* hint that policy agent should enter no-stdout debug mode */
-+ envp[i++] = "DEBUG=kernel";
-+#endif
-+ scratch = buf;
-+
-+ if (device) {
-+ envp[i++] = scratch;
-+ scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
-+ "DEVPATH=/driver/firmware/%s", device) + 1;
-+ }
-+
-+ envp[i++] = scratch;
-+ scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
-+
-+ envp[i++] = scratch;
-+ scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
-+ "FIRMWARE=%s", name) + 1;
-+
-+ envp[i++] = 0;
-+
-+#ifdef DEBUG
-+ dbg("firmware: %s %s %s", argv[0], argv[1], verb);
-+#endif
-+
-+ retval = call_usermodehelper(argv[0], argv, envp);
-+ if (retval) {
-+ printk("call_usermodehelper return %d\n", retval);
-+ }
-+
-+ kfree(buf);
-+ kfree(envp);
-+ return retval;
-+}
-+#else
-+
-+static inline int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+ return -ENOENT;
-+}
-+
-+#endif /* CONFIG_HOTPLUG */
-+
-+struct firmware_priv {
-+ struct completion completion;
-+ struct proc_dir_entry *proc_dir;
-+ struct proc_dir_entry *attr_data;
-+ struct proc_dir_entry *attr_loading;
-+ struct firmware *fw;
-+ int loading;
-+ int abort;
-+ int alloc_size;
-+ struct timer_list timeout;
-+};
-+
-+static int
-+firmware_timeout_show(char *buf, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ return sprintf(buf, "%d\n", loading_timeout);
-+}
-+
-+/**
-+ * firmware_timeout_store:
-+ * Description:
-+ * Sets the number of seconds to wait for the firmware. Once
-+ * this expires an error will be return to the driver and no
-+ * firmware will be provided.
-+ *
-+ * Note: zero means 'wait for ever'
-+ *
-+ **/
-+static int
-+firmware_timeout_store(struct file *file, const char *buf,
-+ unsigned long count, void *data)
-+{
-+ loading_timeout = simple_strtol(buf, NULL, 10);
-+ return count;
-+}
-+
-+static int
-+firmware_loading_show(char *buf, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ return sprintf(buf, "%d\n", fw_priv->loading);
-+}
-+
-+/**
-+ * firmware_loading_store: - loading control file
-+ * Description:
-+ * The relevant values are:
-+ *
-+ * 1: Start a load, discarding any previous partial load.
-+ * 0: Conclude the load and handle the data to the driver code.
-+ * -1: Conclude the load with an error and discard any written data.
-+ **/
-+static int
-+firmware_loading_store(struct file *file, const char *buf,
-+ unsigned long count, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ int prev_loading = fw_priv->loading;
-+
-+ fw_priv->loading = simple_strtol(buf, NULL, 10);
-+
-+ switch (fw_priv->loading) {
-+ case -1:
-+ fw_priv->abort = 1;
-+ wmb();
-+ complete(&fw_priv->completion);
-+ break;
-+ case 1:
-+ kfree(fw_priv->fw->data);
-+ fw_priv->fw->data = NULL;
-+ fw_priv->fw->size = 0;
-+ fw_priv->alloc_size = 0;
-+ break;
-+ case 0:
-+ if (prev_loading == 1)
-+ complete(&fw_priv->completion);
-+ break;
-+ }
-+
-+ return count;
-+}
-+
-+static int
-+firmware_data_read(char *buffer, char **start, off_t offset,
-+ int count, int *eof, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ struct firmware *fw = fw_priv->fw;
-+
-+ if (offset > fw->size)
-+ return 0;
-+ if (offset + count > fw->size)
-+ count = fw->size - offset;
-+
-+ memcpy(buffer, fw->data + offset, count);
-+ *start = (void *) ((long) count);
-+ return count;
-+}
-+static int
-+fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
-+{
-+ u8 *new_data;
-+ int new_size;
-+
-+ if (min_size <= fw_priv->alloc_size)
-+ return 0;
-+ if((min_size % PAGE_SIZE) == 0)
-+ new_size = min_size;
-+ else
-+ new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
-+ new_data = vmalloc(new_size);
-+ if (!new_data) {
-+ printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
-+ /* Make sure that we don't keep incomplete data */
-+ fw_priv->abort = 1;
-+ return -ENOMEM;
-+ }
-+ fw_priv->alloc_size = new_size;
-+ if (fw_priv->fw->data) {
-+ memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
-+ vfree(fw_priv->fw->data);
-+ }
-+ fw_priv->fw->data = new_data;
-+ BUG_ON(min_size > fw_priv->alloc_size);
-+ return 0;
-+}
-+
-+/**
-+ * firmware_data_write:
-+ *
-+ * Description:
-+ *
-+ * Data written to the 'data' attribute will be later handled to
-+ * the driver as a firmware image.
-+ **/
-+static int
-+firmware_data_write(struct file *file, const char *buffer,
-+ unsigned long count, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ struct firmware *fw = fw_priv->fw;
-+ int offset = file->f_pos;
-+ int retval;
-+
-+ retval = fw_realloc_buffer(fw_priv, offset + count);
-+ if (retval) {
-+ printk("%s: retval:%d\n", __FUNCTION__, retval);
-+ return retval;
-+ }
-+
-+ memcpy(fw->data + offset, buffer, count);
-+
-+ fw->size = max_t(size_t, offset + count, fw->size);
-+ file->f_pos += count;
-+ return count;
-+}
-+
-+static void
-+firmware_class_timeout(u_long data)
-+{
-+ struct firmware_priv *fw_priv = (struct firmware_priv *) data;
-+ fw_priv->abort = 1;
-+ wmb();
-+ complete(&fw_priv->completion);
-+}
-+static int
-+fw_setup_class_device(struct firmware_priv **fw_priv_p,
-+ const char *fw_name, const char *device)
-+{
-+ int retval;
-+ struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
-+ GFP_KERNEL);
-+ *fw_priv_p = fw_priv;
-+ if (!fw_priv) {
-+ retval = -ENOMEM;
-+ goto out;
-+ }
-+ memset(fw_priv, 0, sizeof (*fw_priv));
-+
-+ init_completion(&fw_priv->completion);
-+
-+ fw_priv->timeout.function = firmware_class_timeout;
-+ fw_priv->timeout.data = (u_long) fw_priv;
-+ init_timer(&fw_priv->timeout);
-+
-+ retval = -EAGAIN;
-+ fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
-+ if (!fw_priv->proc_dir)
-+ goto err_free_fw_priv;
-+
-+ fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
-+ fw_priv->proc_dir);
-+ if (!fw_priv->attr_data)
-+ goto err_remove_dir;
-+
-+ fw_priv->attr_data->read_proc = firmware_data_read;
-+ fw_priv->attr_data->write_proc = firmware_data_write;
-+ fw_priv->attr_data->data = fw_priv;
-+
-+ fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
-+ fw_priv->proc_dir);
-+ if (!fw_priv->attr_loading)
-+ goto err_remove_data;
-+
-+ fw_priv->attr_loading->read_proc = firmware_loading_show;
-+ fw_priv->attr_loading->write_proc = firmware_loading_store;
-+ fw_priv->attr_loading->data = fw_priv;
-+
-+ retval = 0;
-+ fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
-+ if (!fw_priv->fw) {
-+ printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
-+ __FUNCTION__);
-+ retval = -ENOMEM;
-+ goto err_remove_loading;
-+ }
-+ memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
-+
-+ goto out;
-+
-+err_remove_loading:
-+ remove_proc_entry("loading", fw_priv->proc_dir);
-+err_remove_data:
-+ remove_proc_entry("data", fw_priv->proc_dir);
-+err_remove_dir:
-+ remove_proc_entry(device, proc_dir);
-+err_free_fw_priv:
-+ kfree(fw_priv);
-+out:
-+ return retval;
-+}
-+static void
-+fw_remove_class_device(struct firmware_priv *fw_priv)
-+{
-+ remove_proc_entry("loading", fw_priv->proc_dir);
-+ remove_proc_entry("data", fw_priv->proc_dir);
-+ remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
-+}
-+
-+/**
-+ * request_firmware: - request firmware to hotplug and wait for it
-+ * Description:
-+ * @firmware will be used to return a firmware image by the name
-+ * of @name for device @device.
-+ *
-+ * Should be called from user context where sleeping is allowed.
-+ *
-+ * @name will be use as $FIRMWARE in the hotplug environment and
-+ * should be distinctive enough not to be confused with any other
-+ * firmware image for this or any other device.
-+ **/
-+int
-+request_firmware(const struct firmware **firmware, const char *name,
-+ const char *device)
-+{
-+ struct firmware_priv *fw_priv;
-+ int retval;
-+
-+ if (!firmware) {
-+ retval = -EINVAL;
-+ goto out;
-+ }
-+ *firmware = NULL;
-+
-+ retval = fw_setup_class_device(&fw_priv, name, device);
-+ if (retval)
-+ goto out;
-+
-+ retval = call_helper("add", name, device);
-+ if (retval)
-+ goto out;
-+ if (loading_timeout) {
-+ fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
-+ add_timer(&fw_priv->timeout);
-+ }
-+
-+ wait_for_completion(&fw_priv->completion);
-+
-+ del_timer(&fw_priv->timeout);
-+ fw_remove_class_device(fw_priv);
-+
-+ if (fw_priv->fw->size && !fw_priv->abort) {
-+ *firmware = fw_priv->fw;
-+ } else {
-+ retval = -ENOENT;
-+ vfree(fw_priv->fw->data);
-+ kfree(fw_priv->fw);
-+ }
-+out:
-+ kfree(fw_priv);
-+ return retval;
-+}
-+
-+void
-+release_firmware(const struct firmware *fw)
-+{
-+ if (fw) {
-+ vfree(fw->data);
-+ kfree(fw);
-+ }
-+}
-+
-+/**
-+ * register_firmware: - provide a firmware image for later usage
-+ *
-+ * Description:
-+ * Make sure that @data will be available by requesting firmware @name.
-+ *
-+ * Note: This will not be possible until some kind of persistence
-+ * is available.
-+ **/
-+void
-+register_firmware(const char *name, const u8 *data, size_t size)
-+{
-+ /* This is meaningless without firmware caching, so until we
-+ * decide if firmware caching is reasonable just leave it as a
-+ * noop */
-+}
-+
-+/* Async support */
-+struct firmware_work {
-+ struct tq_struct work;
-+ struct module *module;
-+ const char *name;
-+ const char *device;
-+ void *context;
-+ void (*cont)(const struct firmware *fw, void *context);
-+};
-+
-+static void
-+request_firmware_work_func(void *arg)
-+{
-+ struct firmware_work *fw_work = arg;
-+ const struct firmware *fw;
-+ if (!arg)
-+ return;
-+ request_firmware(&fw, fw_work->name, fw_work->device);
-+ fw_work->cont(fw, fw_work->context);
-+ release_firmware(fw);
-+ __MOD_DEC_USE_COUNT(fw_work->module);
-+ kfree(fw_work);
-+}
-+
-+/**
-+ * request_firmware_nowait:
-+ *
-+ * Description:
-+ * Asynchronous variant of request_firmware() for contexts where
-+ * it is not possible to sleep.
-+ *
-+ * @cont will be called asynchronously when the firmware request is over.
-+ *
-+ * @context will be passed over to @cont.
-+ *
-+ * @fw may be %NULL if firmware request fails.
-+ *
-+ **/
-+int
-+request_firmware_nowait(
-+ struct module *module,
-+ const char *name, const char *device, void *context,
-+ void (*cont)(const struct firmware *fw, void *context))
-+{
-+ struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
-+ GFP_ATOMIC);
-+ if (!fw_work)
-+ return -ENOMEM;
-+ if (!try_inc_mod_count(module)) {
-+ kfree(fw_work);
-+ return -EFAULT;
-+ }
-+
-+ *fw_work = (struct firmware_work) {
-+ .module = module,
-+ .name = name,
-+ .device = device,
-+ .context = context,
-+ .cont = cont,
-+ };
-+ INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
-+
-+ schedule_task(&fw_work->work);
-+ return 0;
-+}
-+
-+static int __init
-+firmware_class_init(void)
-+{
-+ proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
-+ if (!proc_dir)
-+ return -EAGAIN;
-+ proc_dir_timeout = create_proc_entry("timeout",
-+ 0644 | S_IFREG, proc_dir);
-+ if (!proc_dir_timeout) {
-+ remove_proc_entry("driver/firmware", NULL);
-+ return -EAGAIN;
-+ }
-+ proc_dir_timeout->read_proc = firmware_timeout_show;
-+ proc_dir_timeout->write_proc = firmware_timeout_store;
-+ return 0;
-+}
-+static void __exit
-+firmware_class_exit(void)
-+{
-+ remove_proc_entry("timeout", proc_dir);
-+ remove_proc_entry("driver/firmware", NULL);
-+}
-+
-+module_init(firmware_class_init);
-+module_exit(firmware_class_exit);
-+
-+#ifndef CONFIG_FW_LOADER
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-+#endif
-diff -urN linux-2.4.18/lib/Makefile linux-2.4.18-mh15/lib/Makefile
---- linux-2.4.18/lib/Makefile 2001-09-18 00:31:15.000000000 +0200
-+++ linux-2.4.18-mh15/lib/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -8,13 +8,17 @@
-
- L_TARGET := lib.a
-
--export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
-+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
-+ firmware_class.o
-
- obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
-
-+obj-$(CONFIG_FW_LOADER) += firmware_class.o
- obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
- obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
-
-+include $(TOPDIR)/drivers/bluetooth/Makefile.lib
-+
- ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
- obj-y += dec_and_lock.o
- endif
-diff -urN linux-2.4.18/MAINTAINERS linux-2.4.18-mh15/MAINTAINERS
---- linux-2.4.18/MAINTAINERS 2002-02-25 20:37:52.000000000 +0100
-+++ linux-2.4.18-mh15/MAINTAINERS 2004-08-01 16:26:23.000000000 +0200
-@@ -252,10 +252,88 @@
- L: linux-kernel@vger.kernel.org
- S: Maintained
-
--BLUETOOTH SUBSYSTEM (BlueZ)
-+BLUETOOTH SUBSYSTEM
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
- P: Maxim Krasnyansky
- M: maxk@qualcomm.com
-+L: bluez-devel@lists.sf.net
- W: http://bluez.sf.net
-+W: http://www.bluez.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH RFCOMM LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH BNEP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH CMTP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HIDP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI UART DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH HCI USB DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+S: Maintained
-+
-+BLUETOOTH HCI BCM203X DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BFUSB DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI DTL1 DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BLUECARD DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BT3C DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI BTUART DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+S: Maintained
-+
-+BLUETOOTH HCI VHCI DRIVER
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
- S: Maintained
-
- BTTV VIDEO4LINUX DRIVER
-diff -urN linux-2.4.18/net/bluetooth/af_bluetooth.c linux-2.4.18-mh15/net/bluetooth/af_bluetooth.c
---- linux-2.4.18/net/bluetooth/af_bluetooth.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/af_bluetooth.c 2004-08-01 16:26:23.000000000 +0200
-@@ -25,14 +25,15 @@
- /*
- * BlueZ Bluetooth address family and sockets.
- *
-- * $Id$
-+ * $Id$
- */
--#define VERSION "1.1"
-+#define VERSION "2.4"
-
- #include <linux/config.h>
- #include <linux/module.h>
-
- #include <linux/types.h>
-+#include <linux/list.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/major.h>
-@@ -40,6 +41,7 @@
- #include <linux/slab.h>
- #include <linux/skbuff.h>
- #include <linux/init.h>
-+#include <linux/poll.h>
- #include <linux/proc_fs.h>
- #include <net/sock.h>
-
-@@ -48,70 +50,79 @@
- #endif
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
-+
-+#ifndef AF_BLUETOOTH_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-
- /* Bluetooth sockets */
--static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
-+#define BLUEZ_MAX_PROTO 7
-+static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
-
- int bluez_sock_register(int proto, struct net_proto_family *ops)
- {
-- if (proto > BLUEZ_MAX_PROTO)
-+ if (proto >= BLUEZ_MAX_PROTO)
- return -EINVAL;
-
-- if (bluez_sock[proto])
-+ if (bluez_proto[proto])
- return -EEXIST;
-
-- bluez_sock[proto] = ops;
-+ bluez_proto[proto] = ops;
- return 0;
- }
-
- int bluez_sock_unregister(int proto)
- {
-- if (proto > BLUEZ_MAX_PROTO)
-+ if (proto >= BLUEZ_MAX_PROTO)
- return -EINVAL;
-
-- if (!bluez_sock[proto])
-+ if (!bluez_proto[proto])
- return -ENOENT;
-
-- bluez_sock[proto] = NULL;
-+ bluez_proto[proto] = NULL;
- return 0;
- }
-
- static int bluez_sock_create(struct socket *sock, int proto)
- {
-- if (proto > BLUEZ_MAX_PROTO)
-+ if (proto >= BLUEZ_MAX_PROTO)
- return -EINVAL;
-
- #if defined(CONFIG_KMOD)
-- if (!bluez_sock[proto]) {
-+ if (!bluez_proto[proto]) {
- char module_name[30];
- sprintf(module_name, "bt-proto-%d", proto);
- request_module(module_name);
- }
- #endif
-
-- if (!bluez_sock[proto])
-+ if (!bluez_proto[proto])
- return -ENOENT;
-
-- return bluez_sock[proto]->create(sock, proto);
-+ return bluez_proto[proto]->create(sock, proto);
-+}
-+
-+void bluez_sock_init(struct socket *sock, struct sock *sk)
-+{
-+ sock_init_data(sock, sk);
-+ INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
- }
-
- void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
- {
-- write_lock(&l->lock);
--
-+ write_lock_bh(&l->lock);
- sk->next = l->head;
- l->head = sk;
- sock_hold(sk);
--
-- write_unlock(&l->lock);
-+ write_unlock_bh(&l->lock);
- }
-
- void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
- {
- struct sock **skp;
-
-- write_lock(&l->lock);
-+ write_lock_bh(&l->lock);
- for (skp = &l->head; *skp; skp = &((*skp)->next)) {
- if (*skp == sk) {
- *skp = sk->next;
-@@ -119,7 +130,163 @@
- break;
- }
- }
-- write_unlock(&l->lock);
-+ write_unlock_bh(&l->lock);
-+}
-+
-+void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
-+{
-+ BT_DBG("parent %p, sk %p", parent, sk);
-+
-+ sock_hold(sk);
-+ list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
-+ bluez_pi(sk)->parent = parent;
-+ parent->ack_backlog++;
-+}
-+
-+static void bluez_accept_unlink(struct sock *sk)
-+{
-+ BT_DBG("sk %p state %d", sk, sk->state);
-+
-+ list_del_init(&bluez_pi(sk)->accept_q);
-+ bluez_pi(sk)->parent->ack_backlog--;
-+ bluez_pi(sk)->parent = NULL;
-+ sock_put(sk);
-+}
-+
-+struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
-+{
-+ struct list_head *p, *n;
-+ struct bluez_pinfo *pi;
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
-+ pi = list_entry(p, struct bluez_pinfo, accept_q);
-+ sk = bluez_sk(pi);
-+
-+ lock_sock(sk);
-+ if (sk->state == BT_CLOSED) {
-+ release_sock(sk);
-+ bluez_accept_unlink(sk);
-+ continue;
-+ }
-+
-+ if (sk->state == BT_CONNECTED || !newsock) {
-+ bluez_accept_unlink(sk);
-+ if (newsock)
-+ sock_graft(sk, newsock);
-+ release_sock(sk);
-+ return sk;
-+ }
-+ release_sock(sk);
-+ }
-+ return NULL;
-+}
-+
-+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
-+{
-+ int noblock = flags & MSG_DONTWAIT;
-+ struct sock *sk = sock->sk;
-+ struct sk_buff *skb;
-+ int copied, err;
-+
-+ BT_DBG("sock %p sk %p len %d", sock, sk, len);
-+
-+ if (flags & (MSG_OOB))
-+ return -EOPNOTSUPP;
-+
-+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
-+ if (sk->shutdown & RCV_SHUTDOWN)
-+ return 0;
-+ return err;
-+ }
-+
-+ msg->msg_namelen = 0;
-+
-+ copied = skb->len;
-+ if (len < copied) {
-+ msg->msg_flags |= MSG_TRUNC;
-+ copied = len;
-+ }
-+
-+ skb->h.raw = skb->data;
-+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-+
-+ skb_free_datagram(sk, skb);
-+
-+ return err ? : copied;
-+}
-+
-+unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
-+{
-+ struct sock *sk = sock->sk;
-+ unsigned int mask = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ poll_wait(file, sk->sleep, wait);
-+
-+ if (sk->err || !skb_queue_empty(&sk->error_queue))
-+ mask |= POLLERR;
-+
-+ if (sk->shutdown == SHUTDOWN_MASK)
-+ mask |= POLLHUP;
-+
-+ if (!skb_queue_empty(&sk->receive_queue) ||
-+ !list_empty(&bluez_pi(sk)->accept_q) ||
-+ (sk->shutdown & RCV_SHUTDOWN))
-+ mask |= POLLIN | POLLRDNORM;
-+
-+ if (sk->state == BT_CLOSED)
-+ mask |= POLLHUP;
-+
-+ if (sk->state == BT_CONNECT ||
-+ sk->state == BT_CONNECT2 ||
-+ sk->state == BT_CONFIG)
-+ return mask;
-+
-+ if (sock_writeable(sk))
-+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-+ else
-+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-+
-+ return mask;
-+}
-+
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ add_wait_queue(sk->sleep, &wait);
-+ while (sk->state != state) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->err) {
-+ err = sock_error(sk);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+ return err;
- }
-
- struct net_proto_family bluez_sock_family_ops =
-@@ -129,9 +296,9 @@
-
- int bluez_init(void)
- {
-- INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
- proc_mkdir("bluetooth", NULL);
-
-@@ -164,5 +331,6 @@
- module_exit(bluez_cleanup);
-
- MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
-+MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
-+MODULE_LICENSE("GPL");
- #endif
-diff -urN linux-2.4.18/net/bluetooth/bnep/bnep.h linux-2.4.18-mh15/net/bluetooth/bnep/bnep.h
---- linux-2.4.18/net/bluetooth/bnep/bnep.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/bnep.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,185 @@
-+/*
-+ BNEP protocol definition for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License, version 2, as
-+ published by the Free Software Foundation.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef _BNEP_H
-+#define _BNEP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+#include "crc32.h"
-+
-+// Limits
-+#define BNEP_MAX_PROTO_FILTERS 5
-+#define BNEP_MAX_MULTICAST_FILTERS 20
-+
-+// UUIDs
-+#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
-+#define BNEP_UUID16 0x02
-+#define BNEP_UUID32 0x04
-+#define BNEP_UUID128 0x16
-+
-+#define BNEP_SVC_PANU 0x1115
-+#define BNEP_SVC_NAP 0x1116
-+#define BNEP_SVC_GN 0x1117
-+
-+// Packet types
-+#define BNEP_GENERAL 0x00
-+#define BNEP_CONTROL 0x01
-+#define BNEP_COMPRESSED 0x02
-+#define BNEP_COMPRESSED_SRC_ONLY 0x03
-+#define BNEP_COMPRESSED_DST_ONLY 0x04
-+
-+// Control types
-+#define BNEP_CMD_NOT_UNDERSTOOD 0x00
-+#define BNEP_SETUP_CONN_REQ 0x01
-+#define BNEP_SETUP_CONN_RSP 0x02
-+#define BNEP_FILTER_NET_TYPE_SET 0x03
-+#define BNEP_FILTER_NET_TYPE_RSP 0x04
-+#define BNEP_FILTER_MULTI_ADDR_SET 0x05
-+#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
-+
-+// Extension types
-+#define BNEP_EXT_CONTROL 0x00
-+
-+// Response messages
-+#define BNEP_SUCCESS 0x00
-+
-+#define BNEP_CONN_INVALID_DST 0x01
-+#define BNEP_CONN_INVALID_SRC 0x02
-+#define BNEP_CONN_INVALID_SVC 0x03
-+#define BNEP_CONN_NOT_ALLOWED 0x04
-+
-+#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
-+#define BNEP_FILTER_INVALID_RANGE 0x02
-+#define BNEP_FILTER_INVALID_MCADDR 0x02
-+#define BNEP_FILTER_LIMIT_REACHED 0x03
-+#define BNEP_FILTER_DENIED_SECURITY 0x04
-+
-+// L2CAP settings
-+#define BNEP_MTU 1691
-+#define BNEP_PSM 0x0f
-+#define BNEP_FLUSH_TO 0xffff
-+#define BNEP_CONNECT_TO 15
-+#define BNEP_FILTER_TO 15
-+
-+// Headers
-+#define BNEP_TYPE_MASK 0x7f
-+#define BNEP_EXT_HEADER 0x80
-+
-+struct bnep_setup_conn_req {
-+ __u8 type;
-+ __u8 ctrl;
-+ __u8 uuid_size;
-+ __u8 service[0];
-+} __attribute__((packed));
-+
-+struct bnep_set_filter_req {
-+ __u8 type;
-+ __u8 ctrl;
-+ __u16 len;
-+ __u8 list[0];
-+} __attribute__((packed));
-+
-+struct bnep_control_rsp {
-+ __u8 type;
-+ __u8 ctrl;
-+ __u16 resp;
-+} __attribute__((packed));
-+
-+struct bnep_ext_hdr {
-+ __u8 type;
-+ __u8 len;
-+ __u8 data[0];
-+} __attribute__((packed));
-+
-+/* BNEP ioctl defines */
-+#define BNEPCONNADD _IOW('B', 200, int)
-+#define BNEPCONNDEL _IOW('B', 201, int)
-+#define BNEPGETCONNLIST _IOR('B', 210, int)
-+#define BNEPGETCONNINFO _IOR('B', 211, int)
-+
-+struct bnep_connadd_req {
-+ int sock; // Connected socket
-+ __u32 flags;
-+ __u16 role;
-+ char device[16]; // Name of the Ethernet device
-+};
-+
-+struct bnep_conndel_req {
-+ __u32 flags;
-+ __u8 dst[ETH_ALEN];
-+};
-+
-+struct bnep_conninfo {
-+ __u32 flags;
-+ __u16 role;
-+ __u16 state;
-+ __u8 dst[ETH_ALEN];
-+ char device[16];
-+};
-+
-+struct bnep_connlist_req {
-+ __u32 cnum;
-+ struct bnep_conninfo *ci;
-+};
-+
-+struct bnep_proto_filter {
-+ __u16 start;
-+ __u16 end;
-+};
-+
-+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
-+int bnep_del_connection(struct bnep_conndel_req *req);
-+int bnep_get_connlist(struct bnep_connlist_req *req);
-+int bnep_get_conninfo(struct bnep_conninfo *ci);
-+
-+// BNEP sessions
-+struct bnep_session {
-+ struct list_head list;
-+
-+ unsigned int role;
-+ unsigned long state;
-+ unsigned long flags;
-+ atomic_t killed;
-+
-+ struct ethhdr eh;
-+ struct msghdr msg;
-+
-+ struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
-+ u64 mc_filter;
-+
-+ struct socket *sock;
-+ struct net_device dev;
-+ struct net_device_stats stats;
-+};
-+
-+int bnep_net_init(struct net_device *dev);
-+int bnep_sock_init(void);
-+int bnep_sock_cleanup(void);
-+
-+static inline int bnep_mc_hash(__u8 *addr)
-+{
-+ return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
-+}
-+
-+#endif
-diff -urN linux-2.4.18/net/bluetooth/bnep/Config.in linux-2.4.18-mh15/net/bluetooth/bnep/Config.in
---- linux-2.4.18/net/bluetooth/bnep/Config.in 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,11 @@
-+#
-+# Bluetooth BNEP layer configuration
-+#
-+
-+dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
-+
-+if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
-+ bool ' Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
-+ bool ' Protocol filter support' CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+fi
-+
-diff -urN linux-2.4.18/net/bluetooth/bnep/core.c linux-2.4.18-mh15/net/bluetooth/bnep/core.c
---- linux-2.4.18/net/bluetooth/bnep/core.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/core.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,718 @@
-+/*
-+ BNEP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2001-2002 Inventel Systemes
-+ Written 2001-2002 by
-+ Clément Moreau <clement.moreau@inventel.fr>
-+ David Libault <david.libault@inventel.fr>
-+
-+ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/init.h>
-+#include <linux/wait.h>
-+#include <linux/errno.h>
-+#include <linux/smp_lock.h>
-+#include <linux/net.h>
-+#include <net/sock.h>
-+
-+#include <linux/socket.h>
-+#include <linux/file.h>
-+
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.2"
-+
-+static LIST_HEAD(bnep_session_list);
-+static DECLARE_RWSEM(bnep_session_sem);
-+
-+static struct bnep_session *__bnep_get_session(u8 *dst)
-+{
-+ struct bnep_session *s;
-+ struct list_head *p;
-+
-+ BT_DBG("");
-+
-+ list_for_each(p, &bnep_session_list) {
-+ s = list_entry(p, struct bnep_session, list);
-+ if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
-+ return s;
-+ }
-+ return NULL;
-+}
-+
-+static void __bnep_link_session(struct bnep_session *s)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&s->list, &bnep_session_list);
-+}
-+
-+static void __bnep_unlink_session(struct bnep_session *s)
-+{
-+ list_del(&s->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static int bnep_send(struct bnep_session *s, void *data, size_t len)
-+{
-+ struct socket *sock = s->sock;
-+ struct iovec iv = { data, len };
-+ s->msg.msg_iov = &iv;
-+ s->msg.msg_iovlen = 1;
-+ return sock->ops->sendmsg(sock, &s->msg, len, NULL);
-+}
-+
-+static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
-+{
-+ struct bnep_control_rsp rsp;
-+ rsp.type = BNEP_CONTROL;
-+ rsp.ctrl = ctrl;
-+ rsp.resp = htons(resp);
-+ return bnep_send(s, &rsp, sizeof(rsp));
-+}
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+static inline void bnep_set_default_proto_filter(struct bnep_session *s)
-+{
-+ /* (IPv4, ARP) */
-+ s->proto_filter[0].start = htons(0x0800);
-+ s->proto_filter[0].end = htons(0x0806);
-+ /* (RARP, AppleTalk) */
-+ s->proto_filter[1].start = htons(0x8035);
-+ s->proto_filter[1].end = htons(0x80F3);
-+ /* (IPX, IPv6) */
-+ s->proto_filter[2].start = htons(0x8137);
-+ s->proto_filter[2].end = htons(0x86DD);
-+}
-+#endif
-+
-+static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
-+{
-+ int n;
-+
-+ if (len < 2)
-+ return -EILSEQ;
-+
-+ n = ntohs(get_unaligned(data));
-+ data++; len -= 2;
-+
-+ if (len < n)
-+ return -EILSEQ;
-+
-+ BT_DBG("filter len %d", n);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ n /= 4;
-+ if (n <= BNEP_MAX_PROTO_FILTERS) {
-+ struct bnep_proto_filter *f = s->proto_filter;
-+ int i;
-+
-+ for (i = 0; i < n; i++) {
-+ f[i].start = get_unaligned(data++);
-+ f[i].end = get_unaligned(data++);
-+
-+ BT_DBG("proto filter start %d end %d",
-+ f[i].start, f[i].end);
-+ }
-+
-+ if (i < BNEP_MAX_PROTO_FILTERS)
-+ memset(f + i, 0, sizeof(*f));
-+
-+ if (n == 0)
-+ bnep_set_default_proto_filter(s);
-+
-+ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
-+ } else {
-+ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
-+ }
-+#else
-+ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-+#endif
-+ return 0;
-+}
-+
-+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
-+{
-+ int n;
-+
-+ if (len < 2)
-+ return -EILSEQ;
-+
-+ n = ntohs(get_unaligned((u16 *) data));
-+ data += 2; len -= 2;
-+
-+ if (len < n)
-+ return -EILSEQ;
-+
-+ BT_DBG("filter len %d", n);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ n /= (ETH_ALEN * 2);
-+
-+ if (n > 0) {
-+ s->mc_filter = 0;
-+
-+ /* Always send broadcast */
-+ set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
-+
-+ /* Add address ranges to the multicast hash */
-+ for (; n > 0; n--) {
-+ u8 a1[6], *a2;
-+
-+ memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
-+ a2 = data; data += ETH_ALEN;
-+
-+ BT_DBG("mc filter %s -> %s",
-+ batostr((void *) a1), batostr((void *) a2));
-+
-+ #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
-+
-+ /* Iterate from a1 to a2 */
-+ set_bit(bnep_mc_hash(a1), &s->mc_filter);
-+ while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
-+ INCA(a1);
-+ set_bit(bnep_mc_hash(a1), &s->mc_filter);
-+ }
-+ }
-+ }
-+
-+ BT_DBG("mc filter hash 0x%llx", s->mc_filter);
-+
-+ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
-+#else
-+ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-+#endif
-+ return 0;
-+}
-+
-+static int bnep_rx_control(struct bnep_session *s, void *data, int len)
-+{
-+ u8 cmd = *(u8 *)data;
-+ int err = 0;
-+
-+ data++; len--;
-+
-+ switch (cmd) {
-+ case BNEP_CMD_NOT_UNDERSTOOD:
-+ case BNEP_SETUP_CONN_REQ:
-+ case BNEP_SETUP_CONN_RSP:
-+ case BNEP_FILTER_NET_TYPE_RSP:
-+ case BNEP_FILTER_MULTI_ADDR_RSP:
-+ /* Ignore these for now */
-+ break;
-+
-+ case BNEP_FILTER_NET_TYPE_SET:
-+ err = bnep_ctrl_set_netfilter(s, data, len);
-+ break;
-+
-+ case BNEP_FILTER_MULTI_ADDR_SET:
-+ err = bnep_ctrl_set_mcfilter(s, data, len);
-+ break;
-+
-+ default: {
-+ u8 pkt[3];
-+ pkt[0] = BNEP_CONTROL;
-+ pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
-+ pkt[2] = cmd;
-+ bnep_send(s, pkt, sizeof(pkt));
-+ }
-+ break;
-+ }
-+
-+ return err;
-+}
-+
-+static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
-+{
-+ struct bnep_ext_hdr *h;
-+ int err = 0;
-+
-+ do {
-+ h = (void *) skb->data;
-+ if (!skb_pull(skb, sizeof(*h))) {
-+ err = -EILSEQ;
-+ break;
-+ }
-+
-+ BT_DBG("type 0x%x len %d", h->type, h->len);
-+
-+ switch (h->type & BNEP_TYPE_MASK) {
-+ case BNEP_EXT_CONTROL:
-+ bnep_rx_control(s, skb->data, skb->len);
-+ break;
-+
-+ default:
-+ /* Unknown extension, skip it. */
-+ break;
-+ }
-+
-+ if (!skb_pull(skb, h->len)) {
-+ err = -EILSEQ;
-+ break;
-+ }
-+ } while (!err && (h->type & BNEP_EXT_HEADER));
-+
-+ return err;
-+}
-+
-+static u8 __bnep_rx_hlen[] = {
-+ ETH_HLEN, /* BNEP_GENERAL */
-+ 0, /* BNEP_CONTROL */
-+ 2, /* BNEP_COMPRESSED */
-+ ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
-+ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
-+};
-+#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1)
-+
-+static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
-+{
-+ struct net_device *dev = &s->dev;
-+ struct sk_buff *nskb;
-+ u8 type;
-+
-+ dev->last_rx = jiffies;
-+ s->stats.rx_bytes += skb->len;
-+
-+ type = *(u8 *) skb->data; skb_pull(skb, 1);
-+
-+ if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
-+ goto badframe;
-+
-+ if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
-+ bnep_rx_control(s, skb->data, skb->len);
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+
-+ skb->mac.raw = skb->data;
-+
-+ /* Verify and pull out header */
-+ if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
-+ goto badframe;
-+
-+ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
-+
-+ if (type & BNEP_EXT_HEADER) {
-+ if (bnep_rx_extension(s, skb) < 0)
-+ goto badframe;
-+ }
-+
-+ /* Strip 802.1p header */
-+ if (ntohs(s->eh.h_proto) == 0x8100) {
-+ if (!skb_pull(skb, 4))
-+ goto badframe;
-+ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
-+ }
-+
-+ /* We have to alloc new skb and copy data here :(. Because original skb
-+ * may not be modified and because of the alignment requirements. */
-+ nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
-+ if (!nskb) {
-+ s->stats.rx_dropped++;
-+ kfree_skb(skb);
-+ return -ENOMEM;
-+ }
-+ skb_reserve(nskb, 2);
-+
-+ /* Decompress header and construct ether frame */
-+ switch (type & BNEP_TYPE_MASK) {
-+ case BNEP_COMPRESSED:
-+ memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
-+ break;
-+
-+ case BNEP_COMPRESSED_SRC_ONLY:
-+ memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
-+ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-+ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
-+ break;
-+
-+ case BNEP_COMPRESSED_DST_ONLY:
-+ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-+ memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
-+ break;
-+
-+ case BNEP_GENERAL:
-+ memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
-+ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
-+ break;
-+ }
-+
-+ memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
-+ kfree_skb(skb);
-+
-+ s->stats.rx_packets++;
-+ nskb->dev = dev;
-+ nskb->ip_summed = CHECKSUM_UNNECESSARY;
-+ nskb->protocol = eth_type_trans(nskb, dev);
-+ netif_rx_ni(nskb);
-+ return 0;
-+
-+badframe:
-+ s->stats.rx_errors++;
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static u8 __bnep_tx_types[] = {
-+ BNEP_GENERAL,
-+ BNEP_COMPRESSED_SRC_ONLY,
-+ BNEP_COMPRESSED_DST_ONLY,
-+ BNEP_COMPRESSED
-+};
-+
-+static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
-+{
-+ struct ethhdr *eh = (void *) skb->data;
-+ struct socket *sock = s->sock;
-+ struct iovec iv[3];
-+ int len = 0, il = 0;
-+ u8 type = 0;
-+
-+ BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
-+
-+ if (!skb->dev) {
-+ /* Control frame sent by us */
-+ goto send;
-+ }
-+
-+ iv[il++] = (struct iovec) { &type, 1 };
-+ len++;
-+
-+ if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
-+ type |= 0x01;
-+
-+ if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
-+ type |= 0x02;
-+
-+ if (type)
-+ skb_pull(skb, ETH_ALEN * 2);
-+
-+ type = __bnep_tx_types[type];
-+ switch (type) {
-+ case BNEP_COMPRESSED_SRC_ONLY:
-+ iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
-+ len += ETH_ALEN;
-+ break;
-+
-+ case BNEP_COMPRESSED_DST_ONLY:
-+ iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
-+ len += ETH_ALEN;
-+ break;
-+ }
-+
-+send:
-+ iv[il++] = (struct iovec) { skb->data, skb->len };
-+ len += skb->len;
-+
-+ /* FIXME: linearize skb */
-+
-+ s->msg.msg_iov = iv;
-+ s->msg.msg_iovlen = il;
-+ len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
-+ kfree_skb(skb);
-+
-+ if (len > 0) {
-+ s->stats.tx_bytes += len;
-+ s->stats.tx_packets++;
-+ return 0;
-+ }
-+
-+ return len;
-+}
-+
-+static int bnep_session(void *arg)
-+{
-+ struct bnep_session *s = arg;
-+ struct net_device *dev = &s->dev;
-+ struct sock *sk = s->sock->sk;
-+ struct sk_buff *skb;
-+ wait_queue_t wait;
-+
-+ BT_DBG("");
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "kbnepd %s", dev->name);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&wait, current);
-+ add_wait_queue(sk->sleep, &wait);
-+ while (!atomic_read(&s->killed)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ // RX
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ bnep_rx_frame(s, skb);
-+ }
-+
-+ if (sk->state != BT_CONNECTED)
-+ break;
-+
-+ // TX
-+ while ((skb = skb_dequeue(&sk->write_queue)))
-+ if (bnep_tx_frame(s, skb))
-+ break;
-+ netif_wake_queue(dev);
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ /* Cleanup session */
-+ down_write(&bnep_session_sem);
-+
-+ /* Delete network device */
-+ unregister_netdev(dev);
-+
-+ /* Release the socket */
-+ fput(s->sock->file);
-+
-+ __bnep_unlink_session(s);
-+
-+ up_write(&bnep_session_sem);
-+ kfree(s);
-+ return 0;
-+}
-+
-+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
-+{
-+ struct net_device *dev;
-+ struct bnep_session *s, *ss;
-+ u8 dst[ETH_ALEN], src[ETH_ALEN];
-+ int err;
-+
-+ BT_DBG("");
-+
-+ baswap((void *) dst, &bluez_pi(sock->sk)->dst);
-+ baswap((void *) src, &bluez_pi(sock->sk)->src);
-+
-+ s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
-+ if (!s)
-+ return -ENOMEM;
-+ memset(s, 0, sizeof(struct bnep_session));
-+
-+ down_write(&bnep_session_sem);
-+
-+ ss = __bnep_get_session(dst);
-+ if (ss && ss->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ dev = &s->dev;
-+
-+ if (*req->device)
-+ strcpy(dev->name, req->device);
-+ else
-+ strcpy(dev->name, "bnep%d");
-+
-+ memset(dev->broadcast, 0xff, ETH_ALEN);
-+
-+ /* This is rx header therefor addresses are swaped.
-+ * ie eh.h_dest is our local address. */
-+ memcpy(s->eh.h_dest, &src, ETH_ALEN);
-+ memcpy(s->eh.h_source, &dst, ETH_ALEN);
-+
-+ s->sock = sock;
-+ s->role = req->role;
-+ s->state = BT_CONNECTED;
-+
-+ s->msg.msg_flags = MSG_NOSIGNAL;
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ /* Set default mc filter */
-+ set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ /* Set default protocol filter */
-+ bnep_set_default_proto_filter(s);
-+#endif
-+
-+ dev->init = bnep_net_init;
-+ dev->priv = s;
-+ err = register_netdev(dev);
-+ if (err) {
-+ goto failed;
-+ }
-+
-+ __bnep_link_session(s);
-+
-+ err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (err < 0) {
-+ /* Session thread start failed, gotta cleanup. */
-+ unregister_netdev(dev);
-+ __bnep_unlink_session(s);
-+ goto failed;
-+ }
-+
-+ up_write(&bnep_session_sem);
-+ strcpy(req->device, dev->name);
-+ return 0;
-+
-+failed:
-+ up_write(&bnep_session_sem);
-+ kfree(s);
-+ return err;
-+}
-+
-+int bnep_del_connection(struct bnep_conndel_req *req)
-+{
-+ struct bnep_session *s;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&bnep_session_sem);
-+
-+ s = __bnep_get_session(req->dst);
-+ if (s) {
-+ /* Wakeup user-space which is polling for socket errors.
-+ * This is temporary hack untill we have shutdown in L2CAP */
-+ s->sock->sk->err = EUNATCH;
-+
-+ /* Kill session thread */
-+ atomic_inc(&s->killed);
-+ wake_up_interruptible(s->sock->sk->sleep);
-+ } else
-+ err = -ENOENT;
-+
-+ up_read(&bnep_session_sem);
-+ return err;
-+}
-+
-+static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
-+{
-+ memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
-+ strcpy(ci->device, s->dev.name);
-+ ci->flags = s->flags;
-+ ci->state = s->state;
-+ ci->role = s->role;
-+}
-+
-+int bnep_get_connlist(struct bnep_connlist_req *req)
-+{
-+ struct list_head *p;
-+ int err = 0, n = 0;
-+
-+ down_read(&bnep_session_sem);
-+
-+ list_for_each(p, &bnep_session_list) {
-+ struct bnep_session *s;
-+ struct bnep_conninfo ci;
-+
-+ s = list_entry(p, struct bnep_session, list);
-+
-+ __bnep_copy_ci(&ci, s);
-+
-+ if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (++n >= req->cnum)
-+ break;
-+
-+ req->ci++;
-+ }
-+ req->cnum = n;
-+
-+ up_read(&bnep_session_sem);
-+ return err;
-+}
-+
-+int bnep_get_conninfo(struct bnep_conninfo *ci)
-+{
-+ struct bnep_session *s;
-+ int err = 0;
-+
-+ down_read(&bnep_session_sem);
-+
-+ s = __bnep_get_session(ci->dst);
-+ if (s)
-+ __bnep_copy_ci(ci, s);
-+ else
-+ err = -ENOENT;
-+
-+ up_read(&bnep_session_sem);
-+ return err;
-+}
-+
-+static int __init bnep_init_module(void)
-+{
-+ l2cap_load();
-+
-+ bnep_crc32_init();
-+ bnep_sock_init();
-+
-+ BT_INFO("BlueZ BNEP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
-+ BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
-+ BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
-+ BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
-+
-+ return 0;
-+}
-+
-+static void __exit bnep_cleanup_module(void)
-+{
-+ bnep_sock_cleanup();
-+ bnep_crc32_cleanup();
-+}
-+
-+module_init(bnep_init_module);
-+module_exit(bnep_cleanup_module);
-+
-+MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
-+MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.c linux-2.4.18-mh15/net/bluetooth/bnep/crc32.c
---- linux-2.4.18/net/bluetooth/bnep/crc32.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/crc32.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,59 @@
-+/*
-+ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
-+ *
-+ * FIXME: Remove in 2.5
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <asm/atomic.h>
-+
-+#include "crc32.h"
-+
-+#define CRCPOLY_BE 0x04c11db7
-+#define CRC_BE_BITS 8
-+
-+static u32 *bnep_crc32_table;
-+
-+/*
-+ * This code is in the public domain; copyright abandoned.
-+ * Liability for non-performance of this code is limited to the amount
-+ * you paid for it. Since it is distributed for free, your refund will
-+ * be very very small. If it breaks, you get to keep both pieces.
-+ */
-+u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
-+{
-+ while (len--)
-+ crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
-+
-+ return crc;
-+}
-+
-+int __init bnep_crc32_init(void)
-+{
-+ unsigned i, j;
-+ u32 crc = 0x80000000;
-+
-+ bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
-+ if (!bnep_crc32_table)
-+ return -ENOMEM;
-+
-+ bnep_crc32_table[0] = 0;
-+
-+ for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
-+ crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
-+ for (j = 0; j < i; j++)
-+ bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
-+ }
-+ return 0;
-+}
-+
-+void __exit bnep_crc32_cleanup(void)
-+{
-+ if (bnep_crc32_table)
-+ kfree(bnep_crc32_table);
-+ bnep_crc32_table = NULL;
-+}
-diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.h linux-2.4.18-mh15/net/bluetooth/bnep/crc32.h
---- linux-2.4.18/net/bluetooth/bnep/crc32.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/crc32.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,10 @@
-+/*
-+ * crc32.h
-+ * See crc32.c for license and changes
-+ *
-+ * FIXME: Remove in 2.5
-+ */
-+
-+int bnep_crc32_init(void);
-+void bnep_crc32_cleanup(void);
-+u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len);
-diff -urN linux-2.4.18/net/bluetooth/bnep/Makefile linux-2.4.18-mh15/net/bluetooth/bnep/Makefile
---- linux-2.4.18/net/bluetooth/bnep/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth BNEP layer
-+#
-+
-+O_TARGET := bnep.o
-+
-+obj-y := core.o sock.o netdev.o crc32.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/bnep/netdev.c linux-2.4.18-mh15/net/bluetooth/bnep/netdev.c
---- linux-2.4.18/net/bluetooth/bnep/netdev.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/netdev.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,254 @@
-+/*
-+ BNEP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2001-2002 Inventel Systemes
-+ Written 2001-2002 by
-+ Clément Moreau <clement.moreau@inventel.fr>
-+ David Libault <david.libault@inventel.fr>
-+
-+ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/socket.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/wait.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+#define BNEP_TX_QUEUE_LEN 20
-+
-+static int bnep_net_open(struct net_device *dev)
-+{
-+ netif_start_queue(dev);
-+ return 0;
-+}
-+
-+static int bnep_net_close(struct net_device *dev)
-+{
-+ netif_stop_queue(dev);
-+ return 0;
-+}
-+
-+static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
-+{
-+ struct bnep_session *s = dev->priv;
-+ return &s->stats;
-+}
-+
-+static void bnep_net_set_mc_list(struct net_device *dev)
-+{
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ struct bnep_session *s = dev->priv;
-+ struct sock *sk = s->sock->sk;
-+ struct bnep_set_filter_req *r;
-+ struct sk_buff *skb;
-+ int size;
-+
-+ BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
-+
-+ size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
-+ skb = alloc_skb(size, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s Multicast list allocation failed", dev->name);
-+ return;
-+ }
-+
-+ r = (void *) skb->data;
-+ __skb_put(skb, sizeof(*r));
-+
-+ r->type = BNEP_CONTROL;
-+ r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
-+
-+ if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
-+ u8 start[ETH_ALEN] = { 0x01 };
-+
-+ /* Request all addresses */
-+ memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
-+ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+ r->len = htons(ETH_ALEN * 2);
-+ } else {
-+ struct dev_mc_list *dmi = dev->mc_list;
-+ int i, len = skb->len;
-+
-+ if (dev->flags & IFF_BROADCAST) {
-+ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+ }
-+
-+ /* FIXME: We should group addresses here. */
-+
-+ for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
-+ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-+ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-+ dmi = dmi->next;
-+ }
-+ r->len = htons(skb->len - len);
-+ }
-+
-+ skb_queue_tail(&sk->write_queue, skb);
-+ wake_up_interruptible(sk->sleep);
-+#endif
-+}
-+
-+static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
-+{
-+ BT_DBG("%s", dev->name);
-+ return 0;
-+}
-+
-+static void bnep_net_timeout(struct net_device *dev)
-+{
-+ BT_DBG("net_timeout");
-+ netif_wake_queue(dev);
-+}
-+
-+static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-+{
-+ return -EINVAL;
-+}
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
-+{
-+ struct ethhdr *eh = (void *) skb->data;
-+
-+ if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
-+ BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb,
-+ eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
-+ eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
-+ return 1;
-+ }
-+ return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+/* Determine ether protocol. Based on eth_type_trans. */
-+static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
-+{
-+ struct ethhdr *eh = (void *) skb->data;
-+
-+ if (ntohs(eh->h_proto) >= 1536)
-+ return eh->h_proto;
-+
-+ if (get_unaligned((u16 *) skb->data) == 0xFFFF)
-+ return htons(ETH_P_802_3);
-+
-+ return htons(ETH_P_802_2);
-+}
-+
-+static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
-+{
-+ u16 proto = bnep_net_eth_proto(skb);
-+ struct bnep_proto_filter *f = s->proto_filter;
-+ int i;
-+
-+ for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
-+ if (proto >= f[i].start && proto <= f[i].end)
-+ return 0;
-+ }
-+
-+ BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
-+ return 1;
-+}
-+#endif
-+
-+static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct bnep_session *s = dev->priv;
-+ struct sock *sk = s->sock->sk;
-+
-+ BT_DBG("skb %p, dev %p", skb, dev);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ if (bnep_net_mc_filter(skb, s)) {
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ if (bnep_net_proto_filter(skb, s)) {
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+#endif
-+
-+ /*
-+ * We cannot send L2CAP packets from here as we are potentially in a bh.
-+ * So we have to queue them and wake up session thread which is sleeping
-+ * on the sk->sleep.
-+ */
-+ dev->trans_start = jiffies;
-+ skb_queue_tail(&sk->write_queue, skb);
-+ wake_up_interruptible(sk->sleep);
-+
-+ if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
-+ BT_DBG("tx queue is full");
-+
-+ /* Stop queuing.
-+ * Session thread will do netif_wake_queue() */
-+ netif_stop_queue(dev);
-+ }
-+
-+ return 0;
-+}
-+
-+int bnep_net_init(struct net_device *dev)
-+{
-+ struct bnep_session *s = dev->priv;
-+
-+ memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
-+ dev->addr_len = ETH_ALEN;
-+
-+ ether_setup(dev);
-+
-+ dev->open = bnep_net_open;
-+ dev->stop = bnep_net_close;
-+ dev->hard_start_xmit = bnep_net_xmit;
-+ dev->get_stats = bnep_net_get_stats;
-+ dev->do_ioctl = bnep_net_ioctl;
-+ dev->set_mac_address = bnep_net_set_mac_addr;
-+ dev->set_multicast_list = bnep_net_set_mc_list;
-+
-+ dev->watchdog_timeo = HZ * 2;
-+ dev->tx_timeout = bnep_net_timeout;
-+
-+ return 0;
-+}
-diff -urN linux-2.4.18/net/bluetooth/bnep/sock.c linux-2.4.18-mh15/net/bluetooth/bnep/sock.c
---- linux-2.4.18/net/bluetooth/bnep/sock.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/bnep/sock.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,210 @@
-+/*
-+ BNEP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2001-2002 Inventel Systemes
-+ Written 2001-2002 by
-+ David Libault <david.libault@inventel.fr>
-+
-+ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static int bnep_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct bnep_connlist_req cl;
-+ struct bnep_connadd_req ca;
-+ struct bnep_conndel_req cd;
-+ struct bnep_conninfo ci;
-+ struct socket *nsock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case BNEPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ nsock = sockfd_lookup(ca.sock, &err);
-+ if (!nsock)
-+ return err;
-+
-+ if (nsock->sk->state != BT_CONNECTED) {
-+ fput(nsock->file);
-+ return -EBADFD;
-+ }
-+
-+ err = bnep_add_connection(&ca, nsock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else
-+ fput(nsock->file);
-+
-+ return err;
-+
-+ case BNEPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return bnep_del_connection(&cd);
-+
-+ case BNEPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = bnep_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case BNEPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = bnep_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct proto_ops bnep_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: bnep_sock_release,
-+ ioctl: bnep_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int bnep_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &bnep_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family bnep_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: bnep_sock_create
-+};
-+
-+int bnep_sock_init(void)
-+{
-+ bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
-+ return 0;
-+}
-+
-+int bnep_sock_cleanup(void)
-+{
-+ if (bluez_sock_unregister(BTPROTO_BNEP))
-+ BT_ERR("Can't unregister BNEP socket");
-+ return 0;
-+}
-diff -urN linux-2.4.18/net/bluetooth/cmtp/capi.c linux-2.4.18-mh15/net/bluetooth/cmtp/capi.c
---- linux-2.4.18/net/bluetooth/cmtp/capi.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/cmtp/capi.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,707 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <net/sock.h>
-+
-+#include <linux/capi.h>
-+
-+#include "../drivers/isdn/avmb1/capilli.h"
-+#include "../drivers/isdn/avmb1/capicmd.h"
-+#include "../drivers/isdn/avmb1/capiutil.h"
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define REVISION "1.0"
-+
-+#define CAPI_INTEROPERABILITY 0x20
-+
-+#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-+#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-+#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-+#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-+
-+#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
-+#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
-+
-+#define CAPI_FUNCTION_REGISTER 0
-+#define CAPI_FUNCTION_RELEASE 1
-+#define CAPI_FUNCTION_GET_PROFILE 2
-+#define CAPI_FUNCTION_GET_MANUFACTURER 3
-+#define CAPI_FUNCTION_GET_VERSION 4
-+#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
-+#define CAPI_FUNCTION_MANUFACTURER 6
-+#define CAPI_FUNCTION_LOOPBACK 7
-+
-+static struct capi_driver_interface *di;
-+
-+
-+#define CMTP_MSGNUM 1
-+#define CMTP_APPLID 2
-+#define CMTP_MAPPING 3
-+
-+static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-+{
-+ struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
-+
-+ BT_DBG("session %p application %p appl %d", session, app, appl);
-+
-+ if (!app)
-+ return NULL;
-+
-+ memset(app, 0, sizeof(*app));
-+
-+ app->state = BT_OPEN;
-+ app->appl = appl;
-+
-+ list_add_tail(&app->list, &session->applications);
-+
-+ return app;
-+}
-+
-+static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-+{
-+ BT_DBG("session %p application %p", session, app);
-+
-+ if (app) {
-+ list_del(&app->list);
-+ kfree(app);
-+ }
-+}
-+
-+static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-+{
-+ struct cmtp_application *app;
-+ struct list_head *p, *n;
-+
-+ list_for_each_safe(p, n, &session->applications) {
-+ app = list_entry(p, struct cmtp_application, list);
-+ switch (pattern) {
-+ case CMTP_MSGNUM:
-+ if (app->msgnum == value)
-+ return app;
-+ break;
-+ case CMTP_APPLID:
-+ if (app->appl == value)
-+ return app;
-+ break;
-+ case CMTP_MAPPING:
-+ if (app->mapping == value)
-+ return app;
-+ break;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static int cmtp_msgnum_get(struct cmtp_session *session)
-+{
-+ session->msgnum++;
-+
-+ if ((session->msgnum & 0xff) > 200)
-+ session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-+
-+ return session->msgnum;
-+}
-+
-+
-+static void cmtp_send_interopmsg(struct cmtp_session *session,
-+ __u8 subcmd, __u16 appl, __u16 msgnum,
-+ __u16 function, unsigned char *buf, int len)
-+{
-+ struct sk_buff *skb;
-+ unsigned char *s;
-+
-+ BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
-+
-+ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for interoperability packet");
-+ return;
-+ }
-+
-+ s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-+
-+ capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
-+ capimsg_setu16(s, 2, appl);
-+ capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
-+ capimsg_setu8 (s, 5, subcmd);
-+ capimsg_setu16(s, 6, msgnum);
-+
-+ /* Interoperability selector (Bluetooth Device Management) */
-+ capimsg_setu16(s, 8, 0x0001);
-+
-+ capimsg_setu8 (s, 10, 3 + len);
-+ capimsg_setu16(s, 11, function);
-+ capimsg_setu8 (s, 13, len);
-+
-+ if (len > 0)
-+ memcpy(s + 14, buf, len);
-+
-+ cmtp_send_capimsg(session, skb);
-+}
-+
-+static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+ struct cmtp_application *application;
-+ __u16 appl, msgnum, func, info;
-+ __u32 controller;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ switch (CAPIMSG_SUBCOMMAND(skb->data)) {
-+ case CAPI_CONF:
-+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
-+ info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-+
-+ switch (func) {
-+ case CAPI_FUNCTION_REGISTER:
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
-+ if (application) {
-+ application->state = BT_CONNECTED;
-+ application->msgnum = 0;
-+ application->mapping = CAPIMSG_APPID(skb->data);
-+ wake_up_interruptible(&session->wait);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_RELEASE:
-+ appl = CAPIMSG_APPID(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+ if (application) {
-+ application->state = BT_CLOSED;
-+ application->msgnum = 0;
-+ wake_up_interruptible(&session->wait);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_PROFILE:
-+ controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+
-+ if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
-+ session->ncontroller = controller;
-+ wake_up_interruptible(&session->wait);
-+ break;
-+ }
-+
-+ if (!info && ctrl) {
-+ memcpy(&ctrl->profile,
-+ skb->data + CAPI_MSG_BASELEN + 11,
-+ sizeof(capi_profile));
-+ session->state = BT_CONNECTED;
-+ ctrl->ready(ctrl);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_MANUFACTURER:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
-+
-+ if (!info && ctrl) {
-+ strncpy(ctrl->manu,
-+ skb->data + CAPI_MSG_BASELEN + 15,
-+ skb->data[CAPI_MSG_BASELEN + 14]);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_VERSION:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+ if (!info && ctrl) {
-+ ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
-+ ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
-+ ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
-+ ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_SERIAL_NUMBER:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+ if (!info && ctrl) {
-+ memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
-+ strncpy(ctrl->serial,
-+ skb->data + CAPI_MSG_BASELEN + 17,
-+ skb->data[CAPI_MSG_BASELEN + 16]);
-+ }
-+
-+ break;
-+ }
-+
-+ break;
-+
-+ case CAPI_IND:
-+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-+
-+ if (func == CAPI_FUNCTION_LOOPBACK) {
-+ appl = CAPIMSG_APPID(skb->data);
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+ cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
-+ skb->data + CAPI_MSG_BASELEN + 6,
-+ skb->data[CAPI_MSG_BASELEN + 5]);
-+ }
-+
-+ break;
-+ }
-+
-+ kfree_skb(skb);
-+}
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+ struct cmtp_application *application;
-+ __u16 cmd, appl, info;
-+ __u32 ncci, contr;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
-+ cmtp_recv_interopmsg(session, skb);
-+ return;
-+ }
-+
-+ if (session->flags & (1 << CMTP_LOOPBACK)) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
-+ appl = CAPIMSG_APPID(skb->data);
-+ contr = CAPIMSG_CONTROL(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+ if (application) {
-+ appl = application->appl;
-+ CAPIMSG_SETAPPID(skb->data, appl);
-+ } else {
-+ BT_ERR("Can't find application with id %d", appl);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ if ((contr & 0x7f) == 0x01) {
-+ contr = (contr & 0xffffff80) | session->num;
-+ CAPIMSG_SETCONTROL(skb->data, contr);
-+ }
-+
-+ if (!ctrl) {
-+ BT_ERR("Can't find controller %d for message", session->num);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ switch (cmd) {
-+ case CAPI_CONNECT_B3_CONF:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+ info = CAPIMSG_U16(skb->data, 12);
-+
-+ BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info);
-+
-+ if (info == 0)
-+ ctrl->new_ncci(ctrl, appl, ncci, 8);
-+
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+
-+ case CAPI_CONNECT_B3_IND:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+
-+ BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+ ctrl->new_ncci(ctrl, appl, ncci, 8);
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+
-+ case CAPI_DISCONNECT_B3_IND:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+
-+ BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+ if (ncci == 0xffffffff)
-+ BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff");
-+
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ ctrl->free_ncci(ctrl, appl, ncci);
-+ break;
-+
-+ default:
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+ }
-+}
-+
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct cmtp_scb *scb = (void *) skb->cb;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ scb->id = -1;
-+ scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-+
-+ skb_queue_tail(&session->transmit, skb);
-+
-+ cmtp_schedule(session);
-+}
-+
-+
-+static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-+{
-+ BT_DBG("ctrl %p data %p", ctrl, data);
-+
-+ return -EIO;
-+}
-+
-+static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-+{
-+ BT_DBG("ctrl %p", ctrl);
-+
-+ ctrl->reseted(ctrl);
-+}
-+
-+static void cmtp_remove_ctr(struct capi_ctr *ctrl)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+
-+ BT_DBG("ctrl %p", ctrl);
-+
-+ ctrl->suspend_output(ctrl);
-+
-+ atomic_inc(&session->terminate);
-+ cmtp_schedule(session);
-+}
-+
-+static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+ unsigned char buf[8];
-+ int err = 0, nconn, want = rp->level3cnt;
-+
-+ BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
-+ ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-+
-+ application = cmtp_application_add(session, appl);
-+ if (!application) {
-+ BT_ERR("Can't allocate memory for new application");
-+ ctrl->appl_released(ctrl, appl);
-+ return;
-+ }
-+
-+ if (want < 0)
-+ nconn = ctrl->profile.nbchannel * -want;
-+ else
-+ nconn = want;
-+
-+ if (nconn == 0)
-+ nconn = ctrl->profile.nbchannel;
-+
-+ capimsg_setu16(buf, 0, nconn);
-+ capimsg_setu16(buf, 2, rp->datablkcnt);
-+ capimsg_setu16(buf, 4, rp->datablklen);
-+
-+ application->state = BT_CONFIG;
-+ application->msgnum = cmtp_msgnum_get(session);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
-+ CAPI_FUNCTION_REGISTER, buf, 6);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (1) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ if (application->state == BT_CLOSED) {
-+ err = -application->err;
-+ break;
-+ }
-+
-+ if (application->state == BT_CONNECTED)
-+ break;
-+
-+ if (signal_pending(current)) {
-+ err = -EINTR;
-+ break;
-+ }
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ if (err) {
-+ ctrl->appl_released(ctrl, appl);
-+ cmtp_application_del(session, application);
-+ return;
-+ }
-+
-+ ctrl->appl_registered(ctrl, appl);
-+}
-+
-+static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+
-+ BT_DBG("ctrl %p appl %d", ctrl, appl);
-+
-+ application = cmtp_application_get(session, CMTP_APPLID, appl);
-+ if (!application) {
-+ BT_ERR("Can't find application");
-+ return;
-+ }
-+
-+ application->msgnum = cmtp_msgnum_get(session);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
-+ CAPI_FUNCTION_RELEASE, NULL, 0);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (timeo) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (application->state == BT_CLOSED)
-+ break;
-+
-+ if (signal_pending(current))
-+ break;
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ cmtp_application_del(session, application);
-+ ctrl->appl_released(ctrl, appl);
-+}
-+
-+static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ __u16 appl;
-+ __u32 contr;
-+
-+ BT_DBG("ctrl %p skb %p", ctrl, skb);
-+
-+ appl = CAPIMSG_APPID(skb->data);
-+ contr = CAPIMSG_CONTROL(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_APPLID, appl);
-+ if ((!application) || (application->state != BT_CONNECTED)) {
-+ BT_ERR("Can't find application with id %d", appl);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ CAPIMSG_SETAPPID(skb->data, application->mapping);
-+
-+ if ((contr & 0x7f) == session->num) {
-+ contr = (contr & 0xffffff80) | 0x01;
-+ CAPIMSG_SETCONTROL(skb->data, contr);
-+ }
-+
-+ cmtp_send_capimsg(session, skb);
-+}
-+
-+static char *cmtp_procinfo(struct capi_ctr *ctrl)
-+{
-+ return "CAPI Message Transport Protocol";
-+}
-+
-+static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *app;
-+ struct list_head *p, *n;
-+ int len = 0;
-+
-+ len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION);
-+ len += sprintf(page + len, "addr %s\n", session->name);
-+ len += sprintf(page + len, "ctrl %d\n", session->num);
-+
-+ list_for_each_safe(p, n, &session->applications) {
-+ app = list_entry(p, struct cmtp_application, list);
-+ len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
-+ }
-+
-+ if (off + count >= len)
-+ *eof = 1;
-+
-+ if (len < off)
-+ return 0;
-+
-+ *start = page + off;
-+
-+ return ((count < len - off) ? count : len - off);
-+}
-+
-+static struct capi_driver cmtp_driver = {
-+ name: "cmtp",
-+ revision: REVISION,
-+ load_firmware: cmtp_load_firmware,
-+ reset_ctr: cmtp_reset_ctr,
-+ remove_ctr: cmtp_remove_ctr,
-+ register_appl: cmtp_register_appl,
-+ release_appl: cmtp_release_appl,
-+ send_message: cmtp_send_message,
-+ procinfo: cmtp_procinfo,
-+ ctr_read_proc: cmtp_ctr_read_proc,
-+
-+ driver_read_proc: 0,
-+ add_card: 0,
-+};
-+
-+
-+int cmtp_attach_device(struct cmtp_session *session)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+ unsigned char buf[4];
-+
-+ BT_DBG("session %p", session);
-+
-+ capimsg_setu32(buf, 0, 0);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
-+ CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (timeo) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (session->ncontroller)
-+ break;
-+
-+ if (signal_pending(current))
-+ break;
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-+
-+ if (!timeo)
-+ return -ETIMEDOUT;
-+
-+ if (!session->ncontroller)
-+ return -ENODEV;
-+
-+
-+ if (session->ncontroller > 1)
-+ BT_INFO("Setting up only CAPI controller 1");
-+
-+ if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) {
-+ BT_ERR("Can't attach new controller");
-+ return -EBUSY;
-+ }
-+
-+ session->num = session->ctrl->cnr;
-+
-+ BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num);
-+
-+ capimsg_setu32(buf, 0, 1);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_VERSION, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+ return 0;
-+}
-+
-+void cmtp_detach_device(struct cmtp_session *session)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+
-+ BT_DBG("session %p ctrl %p", session, ctrl);
-+
-+ if (!ctrl)
-+ return;
-+
-+ ctrl->reseted(ctrl);
-+
-+ di->detach_ctr(ctrl);
-+}
-+
-+int cmtp_init_capi(void)
-+{
-+ if (!(di = attach_capi_driver(&cmtp_driver))) {
-+ BT_ERR("Can't attach CAPI driver");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+void cmtp_cleanup_capi(void)
-+{
-+ detach_capi_driver(&cmtp_driver);
-+}
-diff -urN linux-2.4.18/net/bluetooth/cmtp/cmtp.h linux-2.4.18-mh15/net/bluetooth/cmtp/cmtp.h
---- linux-2.4.18/net/bluetooth/cmtp/cmtp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/cmtp/cmtp.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,138 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#ifndef __CMTP_H
-+#define __CMTP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+#define BTNAMSIZ 18
-+
-+/* CMTP ioctl defines */
-+#define CMTPCONNADD _IOW('C', 200, int)
-+#define CMTPCONNDEL _IOW('C', 201, int)
-+#define CMTPGETCONNLIST _IOR('C', 210, int)
-+#define CMTPGETCONNINFO _IOR('C', 211, int)
-+
-+#define CMTP_LOOPBACK 0
-+
-+struct cmtp_connadd_req {
-+ int sock; // Connected socket
-+ __u32 flags;
-+};
-+
-+struct cmtp_conndel_req {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+};
-+
-+struct cmtp_conninfo {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+ __u16 state;
-+ int num;
-+};
-+
-+struct cmtp_connlist_req {
-+ __u32 cnum;
-+ struct cmtp_conninfo *ci;
-+};
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
-+int cmtp_del_connection(struct cmtp_conndel_req *req);
-+int cmtp_get_connlist(struct cmtp_connlist_req *req);
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci);
-+
-+/* CMTP session defines */
-+#define CMTP_INTEROP_TIMEOUT (HZ * 5)
-+#define CMTP_INITIAL_MSGNUM 0xff00
-+
-+struct cmtp_session {
-+ struct list_head list;
-+
-+ struct socket *sock;
-+
-+ bdaddr_t bdaddr;
-+
-+ unsigned long state;
-+ unsigned long flags;
-+
-+ uint mtu;
-+
-+ char name[BTNAMSIZ];
-+
-+ atomic_t terminate;
-+
-+ wait_queue_head_t wait;
-+
-+ int ncontroller;
-+ int num;
-+ struct capi_ctr *ctrl;
-+
-+ struct list_head applications;
-+
-+ unsigned long blockids;
-+ int msgnum;
-+
-+ struct sk_buff_head transmit;
-+
-+ struct sk_buff *reassembly[16];
-+};
-+
-+struct cmtp_application {
-+ struct list_head list;
-+
-+ unsigned long state;
-+ int err;
-+
-+ __u16 appl;
-+ __u16 mapping;
-+
-+ __u16 msgnum;
-+};
-+
-+struct cmtp_scb {
-+ int id;
-+ int data;
-+};
-+
-+int cmtp_attach_device(struct cmtp_session *session);
-+void cmtp_detach_device(struct cmtp_session *session);
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-+
-+static inline void cmtp_schedule(struct cmtp_session *session)
-+{
-+ struct sock *sk = session->sock->sk;
-+
-+ wake_up_interruptible(sk->sleep);
-+}
-+
-+/* CMTP init defines */
-+int cmtp_init_capi(void);
-+int cmtp_init_sockets(void);
-+void cmtp_cleanup_capi(void);
-+void cmtp_cleanup_sockets(void);
-+
-+#endif /* __CMTP_H */
-diff -urN linux-2.4.18/net/bluetooth/cmtp/Config.in linux-2.4.18-mh15/net/bluetooth/cmtp/Config.in
---- linux-2.4.18/net/bluetooth/cmtp/Config.in 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/cmtp/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,7 @@
-+#
-+# Bluetooth CMTP layer configuration
-+#
-+
-+if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then
-+ dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP
-+fi
-diff -urN linux-2.4.18/net/bluetooth/cmtp/core.c linux-2.4.18-mh15/net/bluetooth/cmtp/core.c
---- linux-2.4.18/net/bluetooth/cmtp/core.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/cmtp/core.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,515 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <linux/init.h>
-+#include <net/sock.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.0"
-+
-+static DECLARE_RWSEM(cmtp_session_sem);
-+static LIST_HEAD(cmtp_session_list);
-+
-+static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-+{
-+ struct cmtp_session *session;
-+ struct list_head *p;
-+
-+ BT_DBG("");
-+
-+ list_for_each(p, &cmtp_session_list) {
-+ session = list_entry(p, struct cmtp_session, list);
-+ if (!bacmp(bdaddr, &session->bdaddr))
-+ return session;
-+ }
-+ return NULL;
-+}
-+
-+static void __cmtp_link_session(struct cmtp_session *session)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&session->list, &cmtp_session_list);
-+}
-+
-+static void __cmtp_unlink_session(struct cmtp_session *session)
-+{
-+ list_del(&session->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-+{
-+ bacpy(&ci->bdaddr, &session->bdaddr);
-+
-+ ci->flags = session->flags;
-+ ci->state = session->state;
-+
-+ ci->num = session->num;
-+}
-+
-+
-+static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-+{
-+ int i, id = -1;
-+
-+ for (i = 0; i < 16; i++)
-+ if (!test_and_set_bit(i, &session->blockids)) {
-+ id = i;
-+ break;
-+ }
-+
-+ return id;
-+}
-+
-+static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-+{
-+ clear_bit(id, &session->blockids);
-+}
-+
-+static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-+{
-+ struct sk_buff *skb = session->reassembly[id], *nskb;
-+ int size;
-+
-+ BT_DBG("session %p buf %p count %d", session, buf, count);
-+
-+ size = (skb) ? skb->len + count : count;
-+
-+ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for CAPI message");
-+ return;
-+ }
-+
-+ if (skb && (skb->len > 0))
-+ memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
-+
-+ memcpy(skb_put(nskb, count), buf, count);
-+
-+ session->reassembly[id] = nskb;
-+
-+ if (skb)
-+ kfree_skb(skb);
-+}
-+
-+static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ __u8 hdr, hdrlen, id;
-+ __u16 len;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ while (skb->len > 0) {
-+ hdr = skb->data[0];
-+
-+ switch (hdr & 0xc0) {
-+ case 0x40:
-+ hdrlen = 2;
-+ len = skb->data[1];
-+ break;
-+ case 0x80:
-+ hdrlen = 3;
-+ len = skb->data[1] | (skb->data[2] << 8);
-+ break;
-+ default:
-+ hdrlen = 1;
-+ len = 0;
-+ break;
-+ }
-+
-+ id = (hdr & 0x3c) >> 2;
-+
-+ BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-+
-+ if (hdrlen + len > skb->len) {
-+ BT_ERR("Wrong size or header information in CMTP frame");
-+ break;
-+ }
-+
-+ if (len == 0) {
-+ skb_pull(skb, hdrlen);
-+ continue;
-+ }
-+
-+ switch (hdr & 0x03) {
-+ case 0x00:
-+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+ cmtp_recv_capimsg(session, session->reassembly[id]);
-+ session->reassembly[id] = NULL;
-+ break;
-+ case 0x01:
-+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+ break;
-+ default:
-+ if (session->reassembly[id] != NULL)
-+ kfree_skb(session->reassembly[id]);
-+ session->reassembly[id] = NULL;
-+ break;
-+ }
-+
-+ skb_pull(skb, hdrlen + len);
-+ }
-+
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-+{
-+ struct socket *sock = session->sock;
-+ struct iovec iv = { data, len };
-+ struct msghdr msg;
-+ int err;
-+
-+ BT_DBG("session %p data %p len %d", session, data, len);
-+
-+ if (!len)
-+ return 0;
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ err = sock->ops->sendmsg(sock, &msg, len, 0);
-+ return err;
-+}
-+
-+static int cmtp_process_transmit(struct cmtp_session *session)
-+{
-+ struct sk_buff *skb, *nskb;
-+ unsigned char *hdr;
-+ unsigned int size, tail;
-+
-+ BT_DBG("session %p", session);
-+
-+ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new frame");
-+ return -ENOMEM;
-+ }
-+
-+ while ((skb = skb_dequeue(&session->transmit))) {
-+ struct cmtp_scb *scb = (void *) skb->cb;
-+
-+ if ((tail = (session->mtu - nskb->len)) < 5) {
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+ skb_trim(nskb, 0);
-+ tail = session->mtu;
-+ }
-+
-+ size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-+
-+ if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
-+ skb_queue_head(&session->transmit, skb);
-+ break;
-+ }
-+
-+ if (size < 256) {
-+ hdr = skb_put(nskb, 2);
-+ hdr[0] = 0x40
-+ | ((scb->id << 2) & 0x3c)
-+ | ((skb->len == size) ? 0x00 : 0x01);
-+ hdr[1] = size;
-+ } else {
-+ hdr = skb_put(nskb, 3);
-+ hdr[0] = 0x80
-+ | ((scb->id << 2) & 0x3c)
-+ | ((skb->len == size) ? 0x00 : 0x01);
-+ hdr[1] = size & 0xff;
-+ hdr[2] = size >> 8;
-+ }
-+
-+ memcpy(skb_put(nskb, size), skb->data, size);
-+ skb_pull(skb, size);
-+
-+ if (skb->len > 0) {
-+ skb_queue_head(&session->transmit, skb);
-+ } else {
-+ cmtp_free_block_id(session, scb->id);
-+ if (scb->data) {
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+ skb_trim(nskb, 0);
-+ }
-+ kfree_skb(skb);
-+ }
-+ }
-+
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+
-+ kfree_skb(nskb);
-+
-+ return skb_queue_len(&session->transmit);
-+}
-+
-+static int cmtp_session(void *arg)
-+{
-+ struct cmtp_session *session = arg;
-+ struct sock *sk = session->sock->sk;
-+ struct sk_buff *skb;
-+ wait_queue_t wait;
-+
-+ BT_DBG("session %p", session);
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "kcmtpd_ctr_%d", session->num);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&wait, current);
-+ add_wait_queue(sk->sleep, &wait);
-+ while (!atomic_read(&session->terminate)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (sk->state != BT_CONNECTED)
-+ break;
-+
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ cmtp_recv_frame(session, skb);
-+ }
-+
-+ cmtp_process_transmit(session);
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ down_write(&cmtp_session_sem);
-+
-+ if (!(session->flags & (1 << CMTP_LOOPBACK)))
-+ cmtp_detach_device(session);
-+
-+ fput(session->sock->file);
-+
-+ __cmtp_unlink_session(session);
-+
-+ up_write(&cmtp_session_sem);
-+
-+ kfree(session);
-+ return 0;
-+}
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-+{
-+ struct cmtp_session *session, *s;
-+ bdaddr_t src, dst;
-+ int i, err;
-+
-+ BT_DBG("");
-+
-+ baswap(&src, &bluez_pi(sock->sk)->src);
-+ baswap(&dst, &bluez_pi(sock->sk)->dst);
-+
-+ session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
-+ if (!session)
-+ return -ENOMEM;
-+ memset(session, 0, sizeof(struct cmtp_session));
-+
-+ down_write(&cmtp_session_sem);
-+
-+ s = __cmtp_get_session(&bluez_pi(sock->sk)->dst);
-+ if (s && s->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst);
-+
-+ session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
-+
-+ BT_DBG("mtu %d", session->mtu);
-+
-+ sprintf(session->name, "%s", batostr(&dst));
-+
-+ session->sock = sock;
-+ session->state = BT_CONFIG;
-+
-+ init_waitqueue_head(&session->wait);
-+
-+ session->ctrl = NULL;
-+ session->msgnum = CMTP_INITIAL_MSGNUM;
-+
-+ INIT_LIST_HEAD(&session->applications);
-+
-+ skb_queue_head_init(&session->transmit);
-+
-+ for (i = 0; i < 16; i++)
-+ session->reassembly[i] = NULL;
-+
-+ session->flags = req->flags;
-+
-+ __cmtp_link_session(session);
-+
-+ err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (err < 0)
-+ goto unlink;
-+
-+ if (!(session->flags & (1 << CMTP_LOOPBACK))) {
-+ err = cmtp_attach_device(session);
-+ if (err < 0)
-+ goto detach;
-+ }
-+
-+ up_write(&cmtp_session_sem);
-+ return 0;
-+
-+detach:
-+ cmtp_detach_device(session);
-+
-+unlink:
-+ __cmtp_unlink_session(session);
-+
-+failed:
-+ up_write(&cmtp_session_sem);
-+ kfree(session);
-+ return err;
-+}
-+
-+int cmtp_del_connection(struct cmtp_conndel_req *req)
-+{
-+ struct cmtp_session *session;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&cmtp_session_sem);
-+
-+ session = __cmtp_get_session(&req->bdaddr);
-+ if (session) {
-+ /* Flush the transmit queue */
-+ skb_queue_purge(&session->transmit);
-+
-+ /* Kill session thread */
-+ atomic_inc(&session->terminate);
-+ cmtp_schedule(session);
-+ } else
-+ err = -ENOENT;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+int cmtp_get_connlist(struct cmtp_connlist_req *req)
-+{
-+ struct list_head *p;
-+ int err = 0, n = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&cmtp_session_sem);
-+
-+ list_for_each(p, &cmtp_session_list) {
-+ struct cmtp_session *session;
-+ struct cmtp_conninfo ci;
-+
-+ session = list_entry(p, struct cmtp_session, list);
-+
-+ __cmtp_copy_session(session, &ci);
-+
-+ if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (++n >= req->cnum)
-+ break;
-+
-+ req->ci++;
-+ }
-+ req->cnum = n;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-+{
-+ struct cmtp_session *session;
-+ int err = 0;
-+
-+ down_read(&cmtp_session_sem);
-+
-+ session = __cmtp_get_session(&ci->bdaddr);
-+ if (session)
-+ __cmtp_copy_session(session, ci);
-+ else
-+ err = -ENOENT;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+
-+int __init init_cmtp(void)
-+{
-+ l2cap_load();
-+
-+ cmtp_init_capi();
-+ cmtp_init_sockets();
-+
-+ BT_INFO("BlueZ CMTP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ return 0;
-+}
-+
-+void __exit exit_cmtp(void)
-+{
-+ cmtp_cleanup_sockets();
-+ cmtp_cleanup_capi();
-+}
-+
-+module_init(init_cmtp);
-+module_exit(exit_cmtp);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/cmtp/Makefile linux-2.4.18-mh15/net/bluetooth/cmtp/Makefile
---- linux-2.4.18/net/bluetooth/cmtp/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/cmtp/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth CMTP layer
-+#
-+
-+O_TARGET := cmtp.o
-+
-+obj-y := core.o sock.o capi.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/cmtp/sock.c linux-2.4.18-mh15/net/bluetooth/cmtp/sock.c
---- linux-2.4.18/net/bluetooth/cmtp/sock.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/cmtp/sock.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,208 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static int cmtp_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct cmtp_connadd_req ca;
-+ struct cmtp_conndel_req cd;
-+ struct cmtp_connlist_req cl;
-+ struct cmtp_conninfo ci;
-+ struct socket *nsock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case CMTPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ nsock = sockfd_lookup(ca.sock, &err);
-+ if (!nsock)
-+ return err;
-+
-+ if (nsock->sk->state != BT_CONNECTED) {
-+ fput(nsock->file);
-+ return -EBADFD;
-+ }
-+
-+ err = cmtp_add_connection(&ca, nsock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else
-+ fput(nsock->file);
-+
-+ return err;
-+
-+ case CMTPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return cmtp_del_connection(&cd);
-+
-+ case CMTPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = cmtp_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case CMTPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = cmtp_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static struct proto_ops cmtp_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: cmtp_sock_release,
-+ ioctl: cmtp_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int cmtp_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &cmtp_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family cmtp_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: cmtp_sock_create
-+};
-+
-+int cmtp_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
-+ BT_ERR("Can't register CMTP socket layer (%d)", err);
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+void cmtp_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
-+ BT_ERR("Can't unregister CMTP socket layer (%d)", err);
-+
-+ return;
-+}
-diff -urN linux-2.4.18/net/bluetooth/Config.in linux-2.4.18-mh15/net/bluetooth/Config.in
---- linux-2.4.18/net/bluetooth/Config.in 2001-06-12 04:15:27.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -1,16 +1,23 @@
- #
--# Bluetooth configuration
-+# Bluetooth subsystem configuration
- #
-
- if [ "$CONFIG_NET" != "n" ]; then
-+
- mainmenu_option next_comment
- comment 'Bluetooth support'
- dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
-
- if [ "$CONFIG_BLUEZ" != "n" ]; then
- dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
-+ dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
-+ source net/bluetooth/rfcomm/Config.in
-+ source net/bluetooth/bnep/Config.in
-+ source net/bluetooth/cmtp/Config.in
-+ source net/bluetooth/hidp/Config.in
- source drivers/bluetooth/Config.in
- fi
-+
- endmenu
- fi
-
-diff -urN linux-2.4.18/net/bluetooth/hci_conn.c linux-2.4.18-mh15/net/bluetooth/hci_conn.c
---- linux-2.4.18/net/bluetooth/hci_conn.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hci_conn.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,435 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * HCI Connection handling.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/notifier.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef HCI_CORE_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+void hci_acl_connect(struct hci_conn *conn)
-+{
-+ struct hci_dev *hdev = conn->hdev;
-+ struct inquiry_entry *ie;
-+ create_conn_cp cp;
-+
-+ BT_DBG("%p", conn);
-+
-+ conn->state = BT_CONNECT;
-+ conn->out = 1;
-+ conn->link_mode = HCI_LM_MASTER;
-+
-+ memset(&cp, 0, sizeof(cp));
-+ bacpy(&cp.bdaddr, &conn->dst);
-+ cp.pscan_rep_mode = 0x02;
-+
-+ if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
-+ inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
-+ cp.pscan_rep_mode = ie->info.pscan_rep_mode;
-+ cp.pscan_mode = ie->info.pscan_mode;
-+ cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000);
-+ }
-+
-+ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
-+ if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
-+ cp.role_switch = 0x01;
-+ else
-+ cp.role_switch = 0x00;
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
-+ CREATE_CONN_CP_SIZE, &cp);
-+}
-+
-+void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
-+{
-+ disconnect_cp cp;
-+
-+ BT_DBG("%p", conn);
-+
-+ conn->state = BT_DISCONN;
-+
-+ cp.handle = __cpu_to_le16(conn->handle);
-+ cp.reason = reason;
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
-+ DISCONNECT_CP_SIZE, &cp);
-+}
-+
-+void hci_add_sco(struct hci_conn *conn, __u16 handle)
-+{
-+ struct hci_dev *hdev = conn->hdev;
-+ add_sco_cp cp;
-+
-+ BT_DBG("%p", conn);
-+
-+ conn->state = BT_CONNECT;
-+ conn->out = 1;
-+
-+ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-+ cp.handle = __cpu_to_le16(handle);
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
-+}
-+
-+static void hci_conn_timeout(unsigned long arg)
-+{
-+ struct hci_conn *conn = (void *)arg;
-+ struct hci_dev *hdev = conn->hdev;
-+
-+ BT_DBG("conn %p state %d", conn, conn->state);
-+
-+ if (atomic_read(&conn->refcnt))
-+ return;
-+
-+ hci_dev_lock(hdev);
-+ if (conn->state == BT_CONNECTED)
-+ hci_acl_disconn(conn, 0x13);
-+ else
-+ conn->state = BT_CLOSED;
-+ hci_dev_unlock(hdev);
-+ return;
-+}
-+
-+static void hci_conn_init_timer(struct hci_conn *conn)
-+{
-+ init_timer(&conn->timer);
-+ conn->timer.function = hci_conn_timeout;
-+ conn->timer.data = (unsigned long)conn;
-+}
-+
-+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
-+{
-+ struct hci_conn *conn;
-+
-+ BT_DBG("%s dst %s", hdev->name, batostr(dst));
-+
-+ if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
-+ return NULL;
-+ memset(conn, 0, sizeof(struct hci_conn));
-+
-+ bacpy(&conn->dst, dst);
-+ conn->type = type;
-+ conn->hdev = hdev;
-+ conn->state = BT_OPEN;
-+
-+ skb_queue_head_init(&conn->data_q);
-+ hci_conn_init_timer(conn);
-+
-+ atomic_set(&conn->refcnt, 0);
-+
-+ hci_dev_hold(hdev);
-+
-+ tasklet_disable(&hdev->tx_task);
-+ conn_hash_add(hdev, conn);
-+ tasklet_enable(&hdev->tx_task);
-+
-+ return conn;
-+}
-+
-+int hci_conn_del(struct hci_conn *conn)
-+{
-+ struct hci_dev *hdev = conn->hdev;
-+
-+ BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
-+
-+ hci_conn_del_timer(conn);
-+
-+ if (conn->type == SCO_LINK) {
-+ struct hci_conn *acl = conn->link;
-+ if (acl) {
-+ acl->link = NULL;
-+ hci_conn_put(acl);
-+ }
-+ } else {
-+ struct hci_conn *sco = conn->link;
-+ if (sco)
-+ sco->link = NULL;
-+
-+ /* Unacked frames */
-+ hdev->acl_cnt += conn->sent;
-+ }
-+
-+ tasklet_disable(&hdev->tx_task);
-+ conn_hash_del(hdev, conn);
-+ tasklet_enable(&hdev->tx_task);
-+
-+ skb_queue_purge(&conn->data_q);
-+
-+ hci_dev_put(hdev);
-+
-+ kfree(conn);
-+ return 0;
-+}
-+
-+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
-+{
-+ int use_src = bacmp(src, BDADDR_ANY);
-+ struct hci_dev *hdev = NULL;
-+ struct list_head *p;
-+
-+ BT_DBG("%s -> %s", batostr(src), batostr(dst));
-+
-+ read_lock_bh(&hdev_list_lock);
-+
-+ list_for_each(p, &hdev_list) {
-+ struct hci_dev *d;
-+ d = list_entry(p, struct hci_dev, list);
-+
-+ if (!test_bit(HCI_UP, &d->flags))
-+ continue;
-+
-+ /* Simple routing:
-+ * No source address - find interface with bdaddr != dst
-+ * Source address - find interface with bdaddr == src
-+ */
-+
-+ if (use_src) {
-+ if (!bacmp(&d->bdaddr, src)) {
-+ hdev = d; break;
-+ }
-+ } else {
-+ if (bacmp(&d->bdaddr, dst)) {
-+ hdev = d; break;
-+ }
-+ }
-+ }
-+
-+ if (hdev)
-+ hci_dev_hold(hdev);
-+
-+ read_unlock_bh(&hdev_list_lock);
-+ return hdev;
-+}
-+
-+/* Create SCO or ACL connection.
-+ * Device _must_ be locked */
-+struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
-+{
-+ struct hci_conn *acl;
-+
-+ BT_DBG("%s dst %s", hdev->name, batostr(dst));
-+
-+ if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
-+ if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
-+ return NULL;
-+ }
-+
-+ hci_conn_hold(acl);
-+
-+ if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
-+ hci_acl_connect(acl);
-+
-+ if (type == SCO_LINK) {
-+ struct hci_conn *sco;
-+
-+ if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
-+ if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
-+ hci_conn_put(acl);
-+ return NULL;
-+ }
-+ }
-+ acl->link = sco;
-+ sco->link = acl;
-+
-+ hci_conn_hold(sco);
-+
-+ if (acl->state == BT_CONNECTED &&
-+ (sco->state == BT_OPEN || sco->state == BT_CLOSED))
-+ hci_add_sco(sco, acl->handle);
-+
-+ return sco;
-+ } else {
-+ return acl;
-+ }
-+}
-+
-+/* Authenticate remote device */
-+int hci_conn_auth(struct hci_conn *conn)
-+{
-+ BT_DBG("conn %p", conn);
-+
-+ if (conn->link_mode & HCI_LM_AUTH)
-+ return 1;
-+
-+ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
-+ auth_requested_cp ar;
-+ ar.handle = __cpu_to_le16(conn->handle);
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-+ AUTH_REQUESTED_CP_SIZE, &ar);
-+ }
-+ return 0;
-+}
-+
-+/* Enable encryption */
-+int hci_conn_encrypt(struct hci_conn *conn)
-+{
-+ BT_DBG("conn %p", conn);
-+
-+ if (conn->link_mode & HCI_LM_ENCRYPT)
-+ return 1;
-+
-+ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
-+ return 0;
-+
-+ if (hci_conn_auth(conn)) {
-+ set_conn_encrypt_cp ce;
-+ ce.handle = __cpu_to_le16(conn->handle);
-+ ce.encrypt = 1;
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
-+ SET_CONN_ENCRYPT_CP_SIZE, &ce);
-+ }
-+ return 0;
-+}
-+
-+/* Drop all connection on the device */
-+void hci_conn_hash_flush(struct hci_dev *hdev)
-+{
-+ struct conn_hash *h = &hdev->conn_hash;
-+ struct list_head *p;
-+
-+ BT_DBG("hdev %s", hdev->name);
-+
-+ p = h->list.next;
-+ while (p != &h->list) {
-+ struct hci_conn *c;
-+
-+ c = list_entry(p, struct hci_conn, list);
-+ p = p->next;
-+
-+ c->state = BT_CLOSED;
-+
-+ hci_proto_disconn_ind(c, 0x16);
-+ hci_conn_del(c);
-+ }
-+}
-+
-+int hci_get_conn_list(unsigned long arg)
-+{
-+ struct hci_conn_list_req req, *cl;
-+ struct hci_conn_info *ci;
-+ struct hci_dev *hdev;
-+ struct list_head *p;
-+ int n = 0, size, err;
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
-+ return -EINVAL;
-+
-+ size = sizeof(req) + req.conn_num * sizeof(*ci);
-+
-+ if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ if (!(hdev = hci_dev_get(req.dev_id))) {
-+ kfree(cl);
-+ return -ENODEV;
-+ }
-+
-+ ci = cl->conn_info;
-+
-+ hci_dev_lock_bh(hdev);
-+ list_for_each(p, &hdev->conn_hash.list) {
-+ register struct hci_conn *c;
-+ c = list_entry(p, struct hci_conn, list);
-+
-+ bacpy(&(ci + n)->bdaddr, &c->dst);
-+ (ci + n)->handle = c->handle;
-+ (ci + n)->type = c->type;
-+ (ci + n)->out = c->out;
-+ (ci + n)->state = c->state;
-+ (ci + n)->link_mode = c->link_mode;
-+ if (++n >= req.conn_num)
-+ break;
-+ }
-+ hci_dev_unlock_bh(hdev);
-+
-+ cl->dev_id = hdev->id;
-+ cl->conn_num = n;
-+ size = sizeof(req) + n * sizeof(*ci);
-+
-+ hci_dev_put(hdev);
-+
-+ err = copy_to_user((void *) arg, cl, size);
-+ kfree(cl);
-+
-+ return err ? -EFAULT : 0;
-+}
-+
-+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
-+{
-+ struct hci_conn_info_req req;
-+ struct hci_conn_info ci;
-+ struct hci_conn *conn;
-+ char *ptr = (void *) arg + sizeof(req);
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ hci_dev_lock_bh(hdev);
-+ conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
-+ if (conn) {
-+ bacpy(&ci.bdaddr, &conn->dst);
-+ ci.handle = conn->handle;
-+ ci.type = conn->type;
-+ ci.out = conn->out;
-+ ci.state = conn->state;
-+ ci.link_mode = conn->link_mode;
-+ }
-+ hci_dev_unlock_bh(hdev);
-+
-+ if (!conn)
-+ return -ENOENT;
-+
-+ return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
-+}
-diff -urN linux-2.4.18/net/bluetooth/hci_core.c linux-2.4.18-mh15/net/bluetooth/hci_core.c
---- linux-2.4.18/net/bluetooth/hci_core.c 2001-11-09 23:21:21.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hci_core.c 2004-08-01 16:26:23.000000000 +0200
-@@ -25,11 +25,12 @@
- /*
- * BlueZ HCI Core.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
-+#include <linux/kmod.h>
-
- #include <linux/types.h>
- #include <linux/errno.h>
-@@ -50,12 +51,11 @@
- #include <asm/unaligned.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
-
- #ifndef HCI_CORE_DEBUG
--#undef DBG
--#define DBG( A... )
-+#undef BT_DBG
-+#define BT_DBG( A... )
- #endif
-
- static void hci_cmd_task(unsigned long arg);
-@@ -63,279 +63,69 @@
- static void hci_tx_task(unsigned long arg);
- static void hci_notify(struct hci_dev *hdev, int event);
-
--static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
-+rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
-
- /* HCI device list */
--struct hci_dev *hdev_list[HCI_MAX_DEV];
--spinlock_t hdev_list_lock;
--#define GET_HDEV(a) (hdev_list[a])
--
--/* HCI protocol list */
--struct hci_proto *hproto_list[HCI_MAX_PROTO];
--#define GET_HPROTO(a) (hproto_list[a])
-+LIST_HEAD(hdev_list);
-+rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
-
--/* HCI notifiers list */
--struct notifier_block *hci_dev_notifier;
--
--/* HCI device notifications */
--int hci_register_notifier(struct notifier_block *nb)
--{
-- int err, i;
-- struct hci_dev *hdev;
--
-- if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
-- return err;
--
-- /* Notify about already registered devices */
-- spin_lock(&hdev_list_lock);
-- for (i = 0; i < HCI_MAX_DEV; i++) {
-- if (!(hdev = GET_HDEV(i)))
-- continue;
-- if (hdev->flags & HCI_UP)
-- (*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
-- }
-- spin_unlock(&hdev_list_lock);
--
-- return 0;
--}
--
--int hci_unregister_notifier(struct notifier_block *nb)
--{
-- return notifier_chain_unregister(&hci_dev_notifier, nb);
--}
--
--static inline void hci_notify(struct hci_dev *hdev, int event)
--{
-- notifier_call_chain(&hci_dev_notifier, event, hdev);
--}
--
--/* Get HCI device by index (device is locked on return)*/
--struct hci_dev *hci_dev_get(int index)
--{
-- struct hci_dev *hdev;
-- DBG("%d", index);
--
-- if (index < 0 || index >= HCI_MAX_DEV)
-- return NULL;
--
-- spin_lock(&hdev_list_lock);
-- if ((hdev = GET_HDEV(index)))
-- hci_dev_hold(hdev);
-- spin_unlock(&hdev_list_lock);
--
-- return hdev;
--}
--
--/* Flush inquiry cache */
--void inquiry_cache_flush(struct inquiry_cache *cache)
--{
-- struct inquiry_entry *next = cache->list, *e;
--
-- DBG("cache %p", cache);
--
-- cache->list = NULL;
-- while ((e = next)) {
-- next = e->next;
-- kfree(e);
-- }
--}
--
--/* Lookup by bdaddr.
-- * Cache must be locked. */
--static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
--{
-- struct inquiry_entry *e;
--
-- DBG("cache %p, %s", cache, batostr(bdaddr));
--
-- for (e = cache->list; e; e = e->next)
-- if (!bacmp(&e->info.bdaddr, bdaddr))
-- break;
--
-- return e;
--}
--
--static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
--{
-- struct inquiry_entry *e;
--
-- DBG("cache %p, %s", cache, batostr(&info->bdaddr));
--
-- inquiry_cache_lock(cache);
--
-- if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
-- /* Entry not in the cache. Add new one. */
-- if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
-- goto unlock;
-- memset(e, 0, sizeof(struct inquiry_entry));
-- e->next = cache->list;
-- cache->list = e;
-- }
--
-- memcpy(&e->info, info, sizeof(inquiry_info));
-- e->timestamp = jiffies;
-- cache->timestamp = jiffies;
--unlock:
-- inquiry_cache_unlock(cache);
--}
--
--static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
--{
-- inquiry_info *info = (inquiry_info *) buf;
-- struct inquiry_entry *e;
-- int copied = 0;
-+/* HCI protocols */
-+#define HCI_MAX_PROTO 2
-+struct hci_proto *hci_proto[HCI_MAX_PROTO];
-
-- inquiry_cache_lock(cache);
--
-- for (e = cache->list; e && copied < num; e = e->next, copied++)
-- memcpy(info++, &e->info, sizeof(inquiry_info));
-+/* HCI notifiers list */
-+static struct notifier_block *hci_notifier;
-
-- inquiry_cache_unlock(cache);
-
-- DBG("cache %p, copied %d", cache, copied);
-- return copied;
--}
-+/* ---- HCI notifications ---- */
-
--/* --------- BaseBand connections --------- */
--static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst)
-+int hci_register_notifier(struct notifier_block *nb)
- {
-- struct hci_conn *conn;
--
-- DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
--
-- if ( conn_hash_lookup(&hdev->conn_hash, handle)) {
-- ERR("%s handle 0x%x already exists", hdev->name, handle);
-- return NULL;
-- }
--
-- if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
-- return NULL;
-- memset(conn, 0, sizeof(struct hci_conn));
--
-- bacpy(&conn->dst, dst);
-- conn->handle = handle;
-- conn->type = type;
-- conn->hdev = hdev;
--
-- skb_queue_head_init(&conn->data_q);
--
-- hci_dev_hold(hdev);
-- conn_hash_add(&hdev->conn_hash, handle, conn);
--
-- return conn;
-+ return notifier_chain_register(&hci_notifier, nb);
- }
-
--static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
-+int hci_unregister_notifier(struct notifier_block *nb)
- {
-- DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
--
-- conn_hash_del(&hdev->conn_hash, conn);
-- hci_dev_put(hdev);
--
-- /* Unacked frames */
-- hdev->acl_cnt += conn->sent;
--
-- skb_queue_purge(&conn->data_q);
--
-- kfree(conn);
-- return 0;
-+ return notifier_chain_unregister(&hci_notifier, nb);
- }
-
--/* Drop all connection on the device */
--static void hci_conn_hash_flush(struct hci_dev *hdev)
-+void hci_notify(struct hci_dev *hdev, int event)
- {
-- struct conn_hash *h = &hdev->conn_hash;
-- struct hci_proto *hp;
-- struct list_head *p;
--
-- DBG("hdev %s", hdev->name);
--
-- p = h->list.next;
-- while (p != &h->list) {
-- struct hci_conn *c;
--
-- c = list_entry(p, struct hci_conn, list);
-- p = p->next;
--
-- if (c->type == ACL_LINK) {
-- /* ACL link notify L2CAP layer */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
-- hp->disconn_ind(c, 0x16);
-- } else {
-- /* SCO link (no notification) */
-- }
--
-- hci_conn_del(hdev, c);
-- }
-+ notifier_call_chain(&hci_notifier, event, hdev);
- }
-
--int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
--{
-- struct inquiry_cache *cache = &hdev->inq_cache;
-- struct inquiry_entry *e;
-- create_conn_cp cc;
-- __u16 clock_offset;
--
-- DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
--
-- if (!(hdev->flags & HCI_UP))
-- return -ENODEV;
--
-- inquiry_cache_lock_bh(cache);
--
-- if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
-- cc.pscan_rep_mode = 0;
-- cc.pscan_mode = 0;
-- clock_offset = 0;
-- } else {
-- cc.pscan_rep_mode = e->info.pscan_rep_mode;
-- cc.pscan_mode = e->info.pscan_mode;
-- clock_offset = __le16_to_cpu(e->info.clock_offset) & 0x8000;
-- }
--
-- inquiry_cache_unlock_bh(cache);
--
-- bacpy(&cc.bdaddr, bdaddr);
-- cc.pkt_type = __cpu_to_le16(hdev->pkt_type);
-- cc.clock_offset = __cpu_to_le16(clock_offset);
--
-- if (lmp_rswitch_capable(hdev))
-- cc.role_switch = 0x01;
-- else
-- cc.role_switch = 0x00;
--
-- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
-+/* ---- HCI hotplug support ---- */
-
-- return 0;
--}
-+#ifdef CONFIG_HOTPLUG
-
--int hci_disconnect(struct hci_conn *conn, __u8 reason)
-+static int hci_run_hotplug(char *dev, char *action)
- {
-- disconnect_cp dc;
--
-- DBG("conn %p handle %d", conn, conn->handle);
-+ char *argv[3], *envp[5], dstr[20], astr[32];
-
-- dc.handle = __cpu_to_le16(conn->handle);
-- dc.reason = reason;
-- hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
-+ sprintf(dstr, "DEVICE=%s", dev);
-+ sprintf(astr, "ACTION=%s", action);
-
-- return 0;
--}
-+ argv[0] = hotplug_path;
-+ argv[1] = "bluetooth";
-+ argv[2] = NULL;
-
--/* --------- HCI request handling ------------ */
--static inline void hci_req_lock(struct hci_dev *hdev)
--{
-- down(&hdev->req_lock);
-+ envp[0] = "HOME=/";
-+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+ envp[2] = dstr;
-+ envp[3] = astr;
-+ envp[4] = NULL;
-+
-+ return call_usermodehelper(argv[0], argv, envp);
- }
-+#else
-+#define hci_run_hotplug(A...)
-+#endif
-
--static inline void hci_req_unlock(struct hci_dev *hdev)
--{
-- up(&hdev->req_lock);
--}
-+/* ---- HCI requests ---- */
-
--static inline void hci_req_complete(struct hci_dev *hdev, int result)
-+void hci_req_complete(struct hci_dev *hdev, int result)
- {
-- DBG("%s result 0x%2.2x", hdev->name, result);
-+ BT_DBG("%s result 0x%2.2x", hdev->name, result);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = result;
-@@ -344,9 +134,9 @@
- }
- }
-
--static inline void hci_req_cancel(struct hci_dev *hdev, int err)
-+void hci_req_cancel(struct hci_dev *hdev, int err)
- {
-- DBG("%s err 0x%2.2x", hdev->name, err);
-+ BT_DBG("%s err 0x%2.2x", hdev->name, err);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = err;
-@@ -356,23 +146,22 @@
- }
-
- /* Execute request and wait for completion. */
--static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-- unsigned long opt, __u32 timeout)
-+static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout)
- {
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
-- DBG("%s start", hdev->name);
-+ BT_DBG("%s start", hdev->name);
-
- hdev->req_status = HCI_REQ_PEND;
-
- add_wait_queue(&hdev->req_wait_q, &wait);
-- current->state = TASK_INTERRUPTIBLE;
-+ set_current_state(TASK_INTERRUPTIBLE);
-
- req(hdev, opt);
- schedule_timeout(timeout);
-
-- current->state = TASK_RUNNING;
-+ set_current_state(TASK_RUNNING);
- remove_wait_queue(&hdev->req_wait_q, &wait);
-
- if (signal_pending(current))
-@@ -394,7 +183,7 @@
-
- hdev->req_status = hdev->req_result = 0;
-
-- DBG("%s end: err %d", hdev->name, err);
-+ BT_DBG("%s end: err %d", hdev->name, err);
-
- return err;
- }
-@@ -412,10 +201,9 @@
- return ret;
- }
-
--/* --------- HCI requests ---------- */
- static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
- {
-- DBG("%s %ld", hdev->name, opt);
-+ BT_DBG("%s %ld", hdev->name, opt);
-
- /* Reset device */
- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
-@@ -423,27 +211,44 @@
-
- static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
- {
-- set_event_flt_cp ec;
-+ set_event_flt_cp ef;
- __u16 param;
-
-- DBG("%s %ld", hdev->name, opt);
-+ BT_DBG("%s %ld", hdev->name, opt);
-
- /* Mandatory initialization */
-
-+ /* Reset */
-+ if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
-+
- /* Read Local Supported Features */
- hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
-
- /* Read Buffer Size (ACL mtu, max pkt, etc.) */
- hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
-
-+#if 0
-+ /* Host buffer size */
-+ {
-+ host_buffer_size_cp bs;
-+ bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
-+ bs.sco_mtu = HCI_MAX_SCO_SIZE;
-+ bs.acl_max_pkt = __cpu_to_le16(0xffff);
-+ bs.sco_max_pkt = __cpu_to_le16(0xffff);
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE,
-+ HOST_BUFFER_SIZE_CP_SIZE, &bs);
-+ }
-+#endif
-+
- /* Read BD Address */
- hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
-
- /* Optional initialization */
-
- /* Clear Event Filters */
-- ec.flt_type = FLT_CLEAR_ALL;
-- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec);
-+ ef.flt_type = FLT_CLEAR_ALL;
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef);
-
- /* Page timeout ~20 secs */
- param = __cpu_to_le16(0x8000);
-@@ -458,7 +263,7 @@
- {
- __u8 scan = opt;
-
-- DBG("%s %x", hdev->name, scan);
-+ BT_DBG("%s %x", hdev->name, scan);
-
- /* Inquiry and Page scans */
- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
-@@ -468,116 +273,273 @@
- {
- __u8 auth = opt;
-
-- DBG("%s %x", hdev->name, auth);
-+ BT_DBG("%s %x", hdev->name, auth);
-
- /* Authentication */
- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
- }
-
--static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
-+static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
- {
-- struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
-- inquiry_cp ic;
-+ __u8 encrypt = opt;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s %x", hdev->name, encrypt);
-
-- /* Start Inquiry */
-- memcpy(&ic.lap, &ir->lap, 3);
-- ic.lenght = ir->length;
-- ic.num_rsp = ir->num_rsp;
-- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
-+ /* Authentication */
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
- }
-
--/* HCI ioctl helpers */
--int hci_dev_open(__u16 dev)
-+/* Get HCI device by index.
-+ * Device is locked on return. */
-+struct hci_dev *hci_dev_get(int index)
- {
- struct hci_dev *hdev;
-- int ret = 0;
--
-- if (!(hdev = hci_dev_get(dev)))
-- return -ENODEV;
-+ struct list_head *p;
-
-- DBG("%s %p", hdev->name, hdev);
-+ BT_DBG("%d", index);
-
-- hci_req_lock(hdev);
-+ if (index < 0)
-+ return NULL;
-
-- if (hdev->flags & HCI_UP) {
-- ret = -EALREADY;
-- goto done;
-+ read_lock(&hdev_list_lock);
-+ list_for_each(p, &hdev_list) {
-+ hdev = list_entry(p, struct hci_dev, list);
-+ if (hdev->id == index) {
-+ hci_dev_hold(hdev);
-+ goto done;
-+ }
- }
-+ hdev = NULL;
-+done:
-+ read_unlock(&hdev_list_lock);
-+ return hdev;
-+}
-
-- if (hdev->open(hdev)) {
-- ret = -EIO;
-- goto done;
-- }
-+/* ---- Inquiry support ---- */
-+void inquiry_cache_flush(struct hci_dev *hdev)
-+{
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ struct inquiry_entry *next = cache->list, *e;
-
-- if (hdev->flags & HCI_NORMAL) {
-- atomic_set(&hdev->cmd_cnt, 1);
-- hdev->flags |= HCI_INIT;
-+ BT_DBG("cache %p", cache);
-
-- //__hci_request(hdev, hci_reset_req, 0, HZ);
-- ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
--
-- hdev->flags &= ~HCI_INIT;
-+ cache->list = NULL;
-+ while ((e = next)) {
-+ next = e->next;
-+ kfree(e);
- }
-+}
-
-- if (!ret) {
-- hdev->flags |= HCI_UP;
-- hci_notify(hdev, HCI_DEV_UP);
-- } else {
-- /* Init failed, cleanup */
-- tasklet_kill(&hdev->rx_task);
-- tasklet_kill(&hdev->tx_task);
-- tasklet_kill(&hdev->cmd_task);
-+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-+{
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ struct inquiry_entry *e;
-
-- skb_queue_purge(&hdev->cmd_q);
-- skb_queue_purge(&hdev->rx_q);
-+ BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-
-- if (hdev->flush)
-- hdev->flush(hdev);
-+ for (e = cache->list; e; e = e->next)
-+ if (!bacmp(&e->info.bdaddr, bdaddr))
-+ break;
-+ return e;
-+}
-
-- if (hdev->sent_cmd) {
-- kfree_skb(hdev->sent_cmd);
-- hdev->sent_cmd = NULL;
-- }
-+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info)
-+{
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ struct inquiry_entry *e;
-
-- hdev->close(hdev);
-- }
-+ BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
-
--done:
-- hci_req_unlock(hdev);
-- hci_dev_put(hdev);
-+ if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
-+ /* Entry not in the cache. Add new one. */
-+ if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
-+ return;
-+ memset(e, 0, sizeof(struct inquiry_entry));
-+ e->next = cache->list;
-+ cache->list = e;
-+ }
-
-- return ret;
-+ memcpy(&e->info, info, sizeof(inquiry_info));
-+ e->timestamp = jiffies;
-+ cache->timestamp = jiffies;
- }
-
--int hci_dev_close(__u16 dev)
-+int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
- {
-- struct hci_dev *hdev;
--
-- if (!(hdev = hci_dev_get(dev)))
-- return -ENODEV;
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ inquiry_info *info = (inquiry_info *) buf;
-+ struct inquiry_entry *e;
-+ int copied = 0;
-
-- DBG("%s %p", hdev->name, hdev);
-+ for (e = cache->list; e && copied < num; e = e->next, copied++)
-+ memcpy(info++, &e->info, sizeof(inquiry_info));
-
-- hci_req_cancel(hdev, ENODEV);
-- hci_req_lock(hdev);
-+ BT_DBG("cache %p, copied %d", cache, copied);
-+ return copied;
-+}
-
-- if (!(hdev->flags & HCI_UP))
-- goto done;
-+static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
-+{
-+ struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
-+ inquiry_cp ic;
-
-- /* Kill RX and TX tasks */
-- tasklet_kill(&hdev->rx_task);
-- tasklet_kill(&hdev->tx_task);
-+ BT_DBG("%s", hdev->name);
-
-- inquiry_cache_flush(&hdev->inq_cache);
-+ if (test_bit(HCI_INQUIRY, &hdev->flags))
-+ return;
-
-- hci_conn_hash_flush(hdev);
-+ /* Start Inquiry */
-+ memcpy(&ic.lap, &ir->lap, 3);
-+ ic.length = ir->length;
-+ ic.num_rsp = ir->num_rsp;
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
-+}
-
-- /* Clear flags */
-- hdev->flags &= HCI_SOCK;
-- hdev->flags |= HCI_NORMAL;
-+int hci_inquiry(unsigned long arg)
-+{
-+ struct hci_inquiry_req ir;
-+ struct hci_dev *hdev;
-+ int err = 0, do_inquiry = 0, max_rsp;
-+ long timeo;
-+ __u8 *buf, *ptr;
-
-+ ptr = (void *) arg;
-+ if (copy_from_user(&ir, ptr, sizeof(ir)))
-+ return -EFAULT;
-+
-+ if (!(hdev = hci_dev_get(ir.dev_id)))
-+ return -ENODEV;
-+
-+ hci_dev_lock_bh(hdev);
-+ if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-+ inquiry_cache_empty(hdev) ||
-+ ir.flags & IREQ_CACHE_FLUSH) {
-+ inquiry_cache_flush(hdev);
-+ do_inquiry = 1;
-+ }
-+ hci_dev_unlock_bh(hdev);
-+
-+ timeo = ir.length * 2 * HZ;
-+ if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-+ goto done;
-+
-+ /* for unlimited number of responses we will use buffer with 255 entries */
-+ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
-+
-+ /* cache_dump can't sleep. Therefore we allocate temp buffer and then
-+ * copy it to the user space.
-+ */
-+ if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto done;
-+ }
-+
-+ hci_dev_lock_bh(hdev);
-+ ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
-+ hci_dev_unlock_bh(hdev);
-+
-+ BT_DBG("num_rsp %d", ir.num_rsp);
-+
-+ if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) +
-+ (sizeof(inquiry_info) * ir.num_rsp))) {
-+ copy_to_user(ptr, &ir, sizeof(ir));
-+ ptr += sizeof(ir);
-+ copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
-+ } else
-+ err = -EFAULT;
-+
-+ kfree(buf);
-+
-+done:
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
-+/* ---- HCI ioctl helpers ---- */
-+
-+int hci_dev_open(__u16 dev)
-+{
-+ struct hci_dev *hdev;
-+ int ret = 0;
-+
-+ if (!(hdev = hci_dev_get(dev)))
-+ return -ENODEV;
-+
-+ BT_DBG("%s %p", hdev->name, hdev);
-+
-+ hci_req_lock(hdev);
-+
-+ if (test_bit(HCI_UP, &hdev->flags)) {
-+ ret = -EALREADY;
-+ goto done;
-+ }
-+
-+ if (hdev->open(hdev)) {
-+ ret = -EIO;
-+ goto done;
-+ }
-+
-+ if (!test_bit(HCI_RAW, &hdev->flags)) {
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ set_bit(HCI_INIT, &hdev->flags);
-+
-+ //__hci_request(hdev, hci_reset_req, 0, HZ);
-+ ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
-+
-+ clear_bit(HCI_INIT, &hdev->flags);
-+ }
-+
-+ if (!ret) {
-+ set_bit(HCI_UP, &hdev->flags);
-+ hci_notify(hdev, HCI_DEV_UP);
-+ } else {
-+ /* Init failed, cleanup */
-+ tasklet_kill(&hdev->rx_task);
-+ tasklet_kill(&hdev->tx_task);
-+ tasklet_kill(&hdev->cmd_task);
-+
-+ skb_queue_purge(&hdev->cmd_q);
-+ skb_queue_purge(&hdev->rx_q);
-+
-+ if (hdev->flush)
-+ hdev->flush(hdev);
-+
-+ if (hdev->sent_cmd) {
-+ kfree_skb(hdev->sent_cmd);
-+ hdev->sent_cmd = NULL;
-+ }
-+
-+ hdev->close(hdev);
-+ hdev->flags = 0;
-+ }
-+
-+done:
-+ hci_req_unlock(hdev);
-+ hci_dev_put(hdev);
-+ return ret;
-+}
-+
-+static int hci_dev_do_close(struct hci_dev *hdev)
-+{
-+ BT_DBG("%s %p", hdev->name, hdev);
-+
-+ hci_req_cancel(hdev, ENODEV);
-+ hci_req_lock(hdev);
-+
-+ if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
-+ hci_req_unlock(hdev);
-+ return 0;
-+ }
-+
-+ /* Kill RX and TX tasks */
-+ tasklet_kill(&hdev->rx_task);
-+ tasklet_kill(&hdev->tx_task);
-+
-+ hci_dev_lock_bh(hdev);
-+ inquiry_cache_flush(hdev);
-+ hci_conn_hash_flush(hdev);
-+ hci_dev_unlock_bh(hdev);
-+
- hci_notify(hdev, HCI_DEV_DOWN);
-
- if (hdev->flush)
-@@ -586,9 +548,9 @@
- /* Reset device */
- skb_queue_purge(&hdev->cmd_q);
- atomic_set(&hdev->cmd_cnt, 1);
-- hdev->flags |= HCI_INIT;
-- __hci_request(hdev, hci_reset_req, 0, HZ);
-- hdev->flags &= ~HCI_INIT;
-+ set_bit(HCI_INIT, &hdev->flags);
-+ __hci_request(hdev, hci_reset_req, 0, HZ/4);
-+ clear_bit(HCI_INIT, &hdev->flags);
-
- /* Kill cmd task */
- tasklet_kill(&hdev->cmd_task);
-@@ -605,17 +567,28 @@
- }
-
- /* After this point our queues are empty
-- * and no tasks are scheduled.
-- */
-+ * and no tasks are scheduled. */
- hdev->close(hdev);
-
--done:
-- hci_req_unlock(hdev);
-- hci_dev_put(hdev);
-+ /* Clear flags */
-+ hdev->flags = 0;
-
-+ hci_req_unlock(hdev);
- return 0;
- }
-
-+int hci_dev_close(__u16 dev)
-+{
-+ struct hci_dev *hdev;
-+ int err;
-+
-+ if (!(hdev = hci_dev_get(dev)))
-+ return -ENODEV;
-+ err = hci_dev_do_close(hdev);
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
- int hci_dev_reset(__u16 dev)
- {
- struct hci_dev *hdev;
-@@ -627,16 +600,17 @@
- hci_req_lock(hdev);
- tasklet_disable(&hdev->tx_task);
-
-- if (!(hdev->flags & HCI_UP))
-+ if (!test_bit(HCI_UP, &hdev->flags))
- goto done;
-
- /* Drop queues */
- skb_queue_purge(&hdev->rx_q);
- skb_queue_purge(&hdev->cmd_q);
-
-- inquiry_cache_flush(&hdev->inq_cache);
--
-+ hci_dev_lock_bh(hdev);
-+ inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
-+ hci_dev_unlock_bh(hdev);
-
- if (hdev->flush)
- hdev->flush(hdev);
-@@ -650,7 +624,6 @@
- tasklet_enable(&hdev->tx_task);
- hci_req_unlock(hdev);
- hci_dev_put(hdev);
--
- return ret;
- }
-
-@@ -669,30 +642,11 @@
- return ret;
- }
-
--int hci_dev_setauth(unsigned long arg)
--{
-- struct hci_dev *hdev;
-- struct hci_dev_req dr;
-- int ret = 0;
--
-- if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-- return -EFAULT;
--
-- if (!(hdev = hci_dev_get(dr.dev_id)))
-- return -ENODEV;
--
-- ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
--
-- hci_dev_put(hdev);
--
-- return ret;
--}
--
--int hci_dev_setscan(unsigned long arg)
-+int hci_dev_cmd(unsigned int cmd, unsigned long arg)
- {
- struct hci_dev *hdev;
- struct hci_dev_req dr;
-- int ret = 0;
-+ int err = 0;
-
- if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
- return -EFAULT;
-@@ -700,75 +654,105 @@
- if (!(hdev = hci_dev_get(dr.dev_id)))
- return -ENODEV;
-
-- ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
--
-- hci_dev_put(hdev);
-+ switch (cmd) {
-+ case HCISETAUTH:
-+ err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-+ break;
-
-- return ret;
--}
-+ case HCISETENCRYPT:
-+ if (!lmp_encrypt_capable(hdev)) {
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-
--int hci_dev_setptype(unsigned long arg)
--{
-- struct hci_dev *hdev;
-- struct hci_dev_req dr;
-- int ret = 0;
-+ if (!test_bit(HCI_AUTH, &hdev->flags)) {
-+ /* Auth must be enabled first */
-+ err = hci_request(hdev, hci_auth_req,
-+ dr.dev_opt, HCI_INIT_TIMEOUT);
-+ if (err)
-+ break;
-+ }
-+
-+ err = hci_request(hdev, hci_encrypt_req,
-+ dr.dev_opt, HCI_INIT_TIMEOUT);
-+ break;
-+
-+ case HCISETSCAN:
-+ err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-+ break;
-+
-+ case HCISETPTYPE:
-+ hdev->pkt_type = (__u16) dr.dev_opt;
-+ break;
-+
-+ case HCISETLINKPOL:
-+ hdev->link_policy = (__u16) dr.dev_opt;
-+ break;
-
-- if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-- return -EFAULT;
-+ case HCISETLINKMODE:
-+ hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
-+ break;
-
-- if (!(hdev = hci_dev_get(dr.dev_id)))
-- return -ENODEV;
-+ case HCISETACLMTU:
-+ hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1);
-+ hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
-+ break;
-
-- hdev->pkt_type = (__u16) dr.dev_opt;
-+ case HCISETSCOMTU:
-+ hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1);
-+ hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
-+ break;
-
-+ default:
-+ err = -EINVAL;
-+ break;
-+ }
- hci_dev_put(hdev);
--
-- return ret;
-+ return err;
- }
-
--int hci_dev_list(unsigned long arg)
-+int hci_get_dev_list(unsigned long arg)
- {
- struct hci_dev_list_req *dl;
- struct hci_dev_req *dr;
-- struct hci_dev *hdev;
-- int i, n, size;
-+ struct list_head *p;
-+ int n = 0, size, err;
- __u16 dev_num;
-
- if (get_user(dev_num, (__u16 *) arg))
- return -EFAULT;
-
-- /* Avoid long loop, overflow */
-- if (dev_num > 2048)
-+ if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
- return -EINVAL;
--
-- size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
-
-- if (verify_area(VERIFY_WRITE, (void *) arg, size))
-- return -EFAULT;
-+ size = sizeof(*dl) + dev_num * sizeof(*dr);
-
- if (!(dl = kmalloc(size, GFP_KERNEL)))
- return -ENOMEM;
-+
- dr = dl->dev_req;
-
-- spin_lock_bh(&hdev_list_lock);
-- for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
-- if ((hdev = hdev_list[i])) {
-- (dr + n)->dev_id = hdev->id;
-- (dr + n)->dev_opt = hdev->flags;
-- n++;
-- }
-+ read_lock_bh(&hdev_list_lock);
-+ list_for_each(p, &hdev_list) {
-+ struct hci_dev *hdev;
-+ hdev = list_entry(p, struct hci_dev, list);
-+ (dr + n)->dev_id = hdev->id;
-+ (dr + n)->dev_opt = hdev->flags;
-+ if (++n >= dev_num)
-+ break;
- }
-- spin_unlock_bh(&hdev_list_lock);
-+ read_unlock_bh(&hdev_list_lock);
-
- dl->dev_num = n;
-- size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
-+ size = sizeof(*dl) + n * sizeof(*dr);
-
-- copy_to_user((void *) arg, dl, size);
-+ err = copy_to_user((void *) arg, dl, size);
-+ kfree(dl);
-
-- return 0;
-+ return err ? -EFAULT : 0;
- }
-
--int hci_dev_info(unsigned long arg)
-+int hci_get_dev_info(unsigned long arg)
- {
- struct hci_dev *hdev;
- struct hci_dev_info di;
-@@ -786,9 +770,11 @@
- di.flags = hdev->flags;
- di.pkt_type = hdev->pkt_type;
- di.acl_mtu = hdev->acl_mtu;
-- di.acl_max = hdev->acl_max;
-+ di.acl_pkts = hdev->acl_pkts;
- di.sco_mtu = hdev->sco_mtu;
-- di.sco_max = hdev->sco_max;
-+ di.sco_pkts = hdev->sco_pkts;
-+ di.link_policy = hdev->link_policy;
-+ di.link_mode = hdev->link_mode;
-
- memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
- memcpy(&di.features, &hdev->features, sizeof(di.features));
-@@ -801,258 +787,168 @@
- return err;
- }
-
--__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
--{
-- __u32 omode = hdev->flags & HCI_MODE_MASK;
--
-- hdev->flags &= ~HCI_MODE_MASK;
-- hdev->flags |= (mode & HCI_MODE_MASK);
-
-- return omode;
--}
-+/* ---- Interface to HCI drivers ---- */
-
--__u32 hci_dev_getmode(struct hci_dev *hdev)
-+/* Register HCI device */
-+int hci_register_dev(struct hci_dev *hdev)
- {
-- return hdev->flags & HCI_MODE_MASK;
--}
-+ struct list_head *head = &hdev_list, *p;
-+ int id = 0;
-
--int hci_conn_list(unsigned long arg)
--{
-- struct hci_conn_list_req req, *cl;
-- struct hci_conn_info *ci;
-- struct hci_dev *hdev;
-- struct list_head *p;
-- int n = 0, size;
-+ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-
-- if (copy_from_user(&req, (void *) arg, sizeof(req)))
-- return -EFAULT;
-+ if (!hdev->open || !hdev->close || !hdev->destruct)
-+ return -EINVAL;
-
-- if (!(hdev = hci_dev_get(req.dev_id)))
-- return -ENODEV;
-+ write_lock_bh(&hdev_list_lock);
-
-- /* Set a limit to avoid overlong loops, and also numeric overflow - AC */
-- if(req.conn_num < 2048)
-- return -EINVAL;
-+ /* Find first available device id */
-+ list_for_each(p, &hdev_list) {
-+ if (list_entry(p, struct hci_dev, list)->id != id)
-+ break;
-+ head = p; id++;
-+ }
-
-- size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
-+ sprintf(hdev->name, "hci%d", id);
-+ hdev->id = id;
-+ list_add(&hdev->list, head);
-
-- if (!(cl = kmalloc(size, GFP_KERNEL)))
-- return -ENOMEM;
-- ci = cl->conn_info;
--
-- local_bh_disable();
-- conn_hash_lock(&hdev->conn_hash);
-- list_for_each(p, &hdev->conn_hash.list) {
-- register struct hci_conn *c;
-- c = list_entry(p, struct hci_conn, list);
-+ atomic_set(&hdev->refcnt, 1);
-+ spin_lock_init(&hdev->lock);
-+
-+ hdev->flags = 0;
-+ hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
-+ hdev->link_mode = (HCI_LM_ACCEPT);
-
-- (ci + n)->handle = c->handle;
-- bacpy(&(ci + n)->bdaddr, &c->dst);
-- n++;
-- }
-- conn_hash_unlock(&hdev->conn_hash);
-- local_bh_enable();
--
-- cl->dev_id = hdev->id;
-- cl->conn_num = n;
-- size = n * sizeof(struct hci_conn_info) + sizeof(req);
-+ tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
-+ tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
-+ tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
-
-- hci_dev_put(hdev);
-+ skb_queue_head_init(&hdev->rx_q);
-+ skb_queue_head_init(&hdev->cmd_q);
-+ skb_queue_head_init(&hdev->raw_q);
-
-- if(copy_to_user((void *) arg, cl, size))
-- return -EFAULT;
-- return 0;
--}
-+ init_waitqueue_head(&hdev->req_wait_q);
-+ init_MUTEX(&hdev->req_lock);
-
--int hci_inquiry(unsigned long arg)
--{
-- struct inquiry_cache *cache;
-- struct hci_inquiry_req ir;
-- struct hci_dev *hdev;
-- int err = 0, do_inquiry = 0;
-- long timeo;
-- __u8 *buf, *ptr;
-+ inquiry_cache_init(hdev);
-
-- ptr = (void *) arg;
-- if (copy_from_user(&ir, ptr, sizeof(ir)))
-- return -EFAULT;
-+ conn_hash_init(hdev);
-
-- if (!(hdev = hci_dev_get(ir.dev_id)))
-- return -ENODEV;
-+ memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-
-- cache = &hdev->inq_cache;
-+ atomic_set(&hdev->promisc, 0);
-
-- inquiry_cache_lock(cache);
-- if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
-- inquiry_cache_flush(cache);
-- do_inquiry = 1;
-- }
-- inquiry_cache_unlock(cache);
-+ MOD_INC_USE_COUNT;
-
-- /* Limit inquiry time, also avoid overflows */
-+ write_unlock_bh(&hdev_list_lock);
-
-- if(ir.length > 2048 || ir.num_rsp > 2048)
-- {
-- err = -EINVAL;
-- goto done;
-- }
-+ hci_notify(hdev, HCI_DEV_REG);
-+ hci_run_hotplug(hdev->name, "register");
-
-- timeo = ir.length * 2 * HZ;
-- if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-- goto done;
-+ return id;
-+}
-
-- /* cache_dump can't sleep. Therefore we allocate temp buffer and then
-- * copy it to the user space.
-- */
-- if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
-- err = -ENOMEM;
-- goto done;
-- }
-- ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
-+/* Unregister HCI device */
-+int hci_unregister_dev(struct hci_dev *hdev)
-+{
-+ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-
-- DBG("num_rsp %d", ir.num_rsp);
-+ write_lock_bh(&hdev_list_lock);
-+ list_del(&hdev->list);
-+ write_unlock_bh(&hdev_list_lock);
-
-- if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
-- copy_to_user(ptr, &ir, sizeof(ir));
-- ptr += sizeof(ir);
-- copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
-- } else
-- err = -EFAULT;
-+ hci_dev_do_close(hdev);
-
-- kfree(buf);
-+ hci_notify(hdev, HCI_DEV_UNREG);
-+ hci_run_hotplug(hdev->name, "unregister");
-
--done:
- hci_dev_put(hdev);
-
-- return err;
-+ MOD_DEC_USE_COUNT;
-+ return 0;
- }
-
--/* Interface to HCI drivers */
--
--/* Register HCI device */
--int hci_register_dev(struct hci_dev *hdev)
-+/* Suspend HCI device */
-+int hci_suspend_dev(struct hci_dev *hdev)
- {
-- int i;
-+ hci_notify(hdev, HCI_DEV_SUSPEND);
-+ hci_run_hotplug(hdev->name, "suspend");
-+ return 0;
-+}
-
-- DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-+/* Resume HCI device */
-+int hci_resume_dev(struct hci_dev *hdev)
-+{
-+ hci_notify(hdev, HCI_DEV_RESUME);
-+ hci_run_hotplug(hdev->name, "resume");
-+ return 0;
-+}
-
-- /* Find free slot */
-- spin_lock_bh(&hdev_list_lock);
-- for (i = 0; i < HCI_MAX_DEV; i++) {
-- if (!hdev_list[i]) {
-- hdev_list[i] = hdev;
--
-- sprintf(hdev->name, "hci%d", i);
-- atomic_set(&hdev->refcnt, 0);
-- hdev->id = i;
-- hdev->flags = HCI_NORMAL;
--
-- hdev->pkt_type = (HCI_DM1 | HCI_DH1);
--
-- tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
-- tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
-- tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
--
-- skb_queue_head_init(&hdev->rx_q);
-- skb_queue_head_init(&hdev->cmd_q);
-- skb_queue_head_init(&hdev->raw_q);
--
-- init_waitqueue_head(&hdev->req_wait_q);
-- init_MUTEX(&hdev->req_lock);
--
-- inquiry_cache_init(&hdev->inq_cache);
--
-- conn_hash_init(&hdev->conn_hash);
--
-- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
--
-- hci_notify(hdev, HCI_DEV_REG);
--
-- MOD_INC_USE_COUNT;
-- break;
-- }
-- }
-- spin_unlock_bh(&hdev_list_lock);
--
-- return (i == HCI_MAX_DEV) ? -1 : i;
--}
--
--/* Unregister HCI device */
--int hci_unregister_dev(struct hci_dev *hdev)
-+/* Receive frame from HCI drivers */
-+int hci_recv_frame(struct sk_buff *skb)
- {
-- int i;
--
-- DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
--
-- if (hdev->flags & HCI_UP)
-- hci_dev_close(hdev->id);
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-
-- /* Find device slot */
-- spin_lock(&hdev_list_lock);
-- for (i = 0; i < HCI_MAX_DEV; i++) {
-- if (hdev_list[i] == hdev) {
-- hdev_list[i] = NULL;
-- MOD_DEC_USE_COUNT;
-- break;
-- }
-+ if (!hdev || (!test_bit(HCI_UP, &hdev->flags) &&
-+ !test_bit(HCI_INIT, &hdev->flags)) ) {
-+ kfree_skb(skb);
-+ return -1;
- }
-- spin_unlock(&hdev_list_lock);
-
-- hci_notify(hdev, HCI_DEV_UNREG);
--
-- /* Sleep while device is in use */
-- while (atomic_read(&hdev->refcnt)) {
-- int sleep_cnt = 100;
-+ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-- DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
-+ /* Incomming skb */
-+ bluez_cb(skb)->incomming = 1;
-
-- sleep_on_timeout(&hdev->req_wait_q, HZ*10);
-- if (!(--sleep_cnt))
-- break;
-- }
-+ /* Time stamp */
-+ do_gettimeofday(&skb->stamp);
-
-+ /* Queue frame for rx task */
-+ skb_queue_tail(&hdev->rx_q, skb);
-+ hci_sched_rx(hdev);
- return 0;
- }
-
--/* Interface to upper protocols */
-+/* ---- Interface to upper protocols ---- */
-
- /* Register/Unregister protocols.
-- * hci_task_lock is used to ensure that no tasks are running.
-- */
--int hci_register_proto(struct hci_proto *hproto)
-+ * hci_task_lock is used to ensure that no tasks are running. */
-+int hci_register_proto(struct hci_proto *hp)
- {
- int err = 0;
-
-- DBG("%p name %s", hproto, hproto->name);
-+ BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
-
-- if (hproto->id >= HCI_MAX_PROTO)
-+ if (hp->id >= HCI_MAX_PROTO)
- return -EINVAL;
-
- write_lock_bh(&hci_task_lock);
-
-- if (!hproto_list[hproto->id])
-- hproto_list[hproto->id] = hproto;
-+ if (!hci_proto[hp->id])
-+ hci_proto[hp->id] = hp;
- else
-- err = -1;
-+ err = -EEXIST;
-
- write_unlock_bh(&hci_task_lock);
-
- return err;
- }
-
--int hci_unregister_proto(struct hci_proto *hproto)
-+int hci_unregister_proto(struct hci_proto *hp)
- {
- int err = 0;
-
-- DBG("%p name %s", hproto, hproto->name);
-+ BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
-
-- if (hproto->id > HCI_MAX_PROTO)
-+ if (hp->id >= HCI_MAX_PROTO)
- return -EINVAL;
-
- write_lock_bh(&hci_task_lock);
-
-- if (hproto_list[hproto->id])
-- hproto_list[hproto->id] = NULL;
-+ if (hci_proto[hp->id])
-+ hci_proto[hp->id] = NULL;
- else
- err = -ENOENT;
-
-@@ -1070,10 +966,14 @@
- return -ENODEV;
- }
-
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+
-+ if (atomic_read(&hdev->promisc)) {
-+ /* Time stamp */
-+ do_gettimeofday(&skb->stamp);
-
-- if (hdev->flags & HCI_SOCK)
- hci_send_to_sock(hdev, skb);
-+ }
-
- /* Get rid of skb owner, prior to sending to the driver. */
- skb_orphan(skb);
-@@ -1081,128 +981,6 @@
- return hdev->send(skb);
- }
-
--/* Connection scheduler */
--static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
--{
-- struct conn_hash *h = &hdev->conn_hash;
-- struct hci_conn *conn = NULL;
-- int num = 0, min = 0xffff;
-- struct list_head *p;
--
-- conn_hash_lock(h);
-- list_for_each(p, &h->list) {
-- register struct hci_conn *c;
--
-- c = list_entry(p, struct hci_conn, list);
--
-- if (c->type != type || skb_queue_empty(&c->data_q))
-- continue;
-- num++;
--
-- if (c->sent < min) {
-- min = c->sent;
-- conn = c;
-- }
-- }
-- conn_hash_unlock(h);
--
-- if (conn) {
-- int q = hdev->acl_cnt / num;
-- *quote = q ? q : 1;
-- } else
-- *quote = 0;
--
-- DBG("conn %p quote %d", conn, *quote);
--
-- return conn;
--}
--
--static inline void hci_sched_acl(struct hci_dev *hdev)
--{
-- struct hci_conn *conn;
-- struct sk_buff *skb;
-- int quote;
--
-- DBG("%s", hdev->name);
--
-- while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-- while (quote && (skb = skb_dequeue(&conn->data_q))) {
-- DBG("skb %p len %d", skb, skb->len);
--
-- hci_send_frame(skb);
--
-- conn->sent++;
-- hdev->acl_cnt--;
-- quote--;
-- }
-- }
--}
--
--/* Schedule SCO */
--static inline void hci_sched_sco(struct hci_dev *hdev)
--{
-- /* FIXME: For now we queue SCO packets to the raw queue
--
-- while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) {
-- hci_send_frame(skb);
-- conn->sco_sent++;
-- hdev->sco_cnt--;
-- }
-- */
--}
--
--/* Get data from the previously sent command */
--static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
--{
-- hci_command_hdr *hc;
--
-- if (!hdev->sent_cmd)
-- return NULL;
--
-- hc = (void *) hdev->sent_cmd->data;
--
-- if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
-- return NULL;
--
-- DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
--
-- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
--}
--
--/* Send raw HCI frame */
--int hci_send_raw(struct sk_buff *skb)
--{
-- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--
-- if (!hdev) {
-- kfree_skb(skb);
-- return -ENODEV;
-- }
--
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
-- if (hdev->flags & HCI_NORMAL) {
-- /* Queue frame according it's type */
-- switch (skb->pkt_type) {
-- case HCI_COMMAND_PKT:
-- skb_queue_tail(&hdev->cmd_q, skb);
-- hci_sched_cmd(hdev);
-- return 0;
--
-- case HCI_ACLDATA_PKT:
-- case HCI_SCODATA_PKT:
-- /* FIXME:
-- * Check header here and queue to apropriate connection.
-- */
-- break;
-- }
-- }
--
-- skb_queue_tail(&hdev->raw_q, skb);
-- hci_sched_tx(hdev);
-- return 0;
--}
--
- /* Send HCI command */
- int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
- {
-@@ -1210,10 +988,10 @@
- hci_command_hdr *hc;
- struct sk_buff *skb;
-
-- DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
-+ BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
-
- if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
-- ERR("%s Can't allocate memory for HCI command", hdev->name);
-+ BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
- return -ENOMEM;
- }
-
-@@ -1224,7 +1002,7 @@
- if (plen)
- memcpy(skb_put(skb, plen), param, plen);
-
-- DBG("skb len %d", skb->len);
-+ BT_DBG("skb len %d", skb->len);
-
- skb->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-@@ -1234,10 +1012,28 @@
- return 0;
- }
-
-+/* Get data from the previously sent command */
-+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
-+{
-+ hci_command_hdr *hc;
-+
-+ if (!hdev->sent_cmd)
-+ return NULL;
-+
-+ hc = (void *) hdev->sent_cmd->data;
-+
-+ if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
-+ return NULL;
-+
-+ BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
-+
-+ return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
-+}
-+
- /* Send ACL data */
- static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
- {
-- int len = skb->len;
-+ int len = skb->len;
- hci_acl_hdr *ah;
-
- ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
-@@ -1252,7 +1048,7 @@
- struct hci_dev *hdev = conn->hdev;
- struct sk_buff *list;
-
-- DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-+ BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-
- skb->dev = (void *) hdev;
- skb->pkt_type = HCI_ACLDATA_PKT;
-@@ -1260,12 +1056,12 @@
-
- if (!(list = skb_shinfo(skb)->frag_list)) {
- /* Non fragmented */
-- DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-+ BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-
- skb_queue_tail(&conn->data_q, skb);
- } else {
- /* Fragmented */
-- DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-+ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- skb_shinfo(skb)->frag_list = NULL;
-
-@@ -1280,7 +1076,7 @@
- skb->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
-
-- DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-+ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- __skb_queue_tail(&conn->data_q, skb);
- } while (list);
-@@ -1298,7 +1094,7 @@
- struct hci_dev *hdev = conn->hdev;
- hci_sco_hdr hs;
-
-- DBG("%s len %d", hdev->name, skb->len);
-+ BT_DBG("%s len %d", hdev->name, skb->len);
-
- if (skb->len > hdev->sco_mtu) {
- kfree_skb(skb);
-@@ -1315,544 +1111,136 @@
- skb->pkt_type = HCI_SCODATA_PKT;
- skb_queue_tail(&conn->data_q, skb);
- hci_sched_tx(hdev);
--
- return 0;
- }
-
--/* Handle HCI Event packets */
--
--/* Command Complete OGF LINK_CTL */
--static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Complete OGF LINK_POLICY */
--static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Complete OGF HOST_CTL */
--static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
-- __u8 status, param;
-- void *sent;
--
--
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- case OCF_RESET:
-- status = *((__u8 *) skb->data);
--
-- hci_req_complete(hdev, status);
-- break;
--
-- case OCF_SET_EVENT_FLT:
-- status = *((__u8 *) skb->data);
--
-- if (status) {
-- DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-- } else {
-- DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-- }
-- break;
--
-- case OCF_WRITE_AUTH_ENABLE:
-- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE)))
-- break;
--
-- status = *((__u8 *) skb->data);
-- param = *((__u8 *) sent);
--
-- if (!status) {
-- if (param == AUTH_ENABLED)
-- hdev->flags |= HCI_AUTH;
-- else
-- hdev->flags &= ~HCI_AUTH;
-- }
-- hci_req_complete(hdev, status);
-- break;
--
-- case OCF_WRITE_CA_TIMEOUT:
-- status = *((__u8 *) skb->data);
--
-- if (status) {
-- DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-- } else {
-- DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-- }
-- break;
--
-- case OCF_WRITE_PG_TIMEOUT:
-- status = *((__u8 *) skb->data);
--
-- if (status) {
-- DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-- } else {
-- DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-- }
-- break;
--
-- case OCF_WRITE_SCAN_ENABLE:
-- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE)))
-- break;
-- status = *((__u8 *) skb->data);
-- param = *((__u8 *) sent);
--
-- DBG("param 0x%x", param);
--
-- if (!status) {
-- switch (param) {
-- case IS_ENA_PS_ENA:
-- hdev->flags |= HCI_PSCAN | HCI_ISCAN;
-- break;
--
-- case IS_ENA_PS_DIS:
-- hdev->flags &= ~HCI_PSCAN;
-- hdev->flags |= HCI_ISCAN;
-- break;
-+/* ---- HCI TX task (outgoing data) ---- */
-
-- case IS_DIS_PS_ENA:
-- hdev->flags &= ~HCI_ISCAN;
-- hdev->flags |= HCI_PSCAN;
-- break;
--
-- default:
-- hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
-- break;
-- };
-- }
-- hci_req_complete(hdev, status);
-- break;
--
-- default:
-- DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Complete OGF INFO_PARAM */
--static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+/* HCI Connection scheduler */
-+static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
- {
-- read_local_features_rp *lf;
-- read_buffer_size_rp *bs;
-- read_bd_addr_rp *ba;
--
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- case OCF_READ_LOCAL_FEATURES:
-- lf = (read_local_features_rp *) skb->data;
--
-- if (lf->status) {
-- DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-- break;
-- }
--
-- memcpy(hdev->features, lf->features, sizeof(hdev->features));
--
-- /* Adjust default settings according to features
-- * supported by device. */
-- if (hdev->features[0] & LMP_3SLOT)
-- hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
--
-- if (hdev->features[0] & LMP_5SLOT)
-- hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
--
-- DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
--
-- break;
--
-- case OCF_READ_BUFFER_SIZE:
-- bs = (read_buffer_size_rp *) skb->data;
--
-- if (bs->status) {
-- DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-- break;
-- }
--
-- hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
-- hdev->sco_mtu = bs->sco_mtu;
-- hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-- hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
--
-- DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-- hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
-+ struct conn_hash *h = &hdev->conn_hash;
-+ struct hci_conn *conn = NULL;
-+ int num = 0, min = ~0;
-+ struct list_head *p;
-
-- break;
-+ /* We don't have to lock device here. Connections are always
-+ * added and removed with TX task disabled. */
-+ list_for_each(p, &h->list) {
-+ struct hci_conn *c;
-+ c = list_entry(p, struct hci_conn, list);
-
-- case OCF_READ_BD_ADDR:
-- ba = (read_bd_addr_rp *) skb->data;
-+ if (c->type != type || c->state != BT_CONNECTED
-+ || skb_queue_empty(&c->data_q))
-+ continue;
-+ num++;
-
-- if (!ba->status) {
-- bacpy(&hdev->bdaddr, &ba->bdaddr);
-- } else {
-- DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-+ if (c->sent < min) {
-+ min = c->sent;
-+ conn = c;
- }
-+ }
-
-- hci_req_complete(hdev, ba->status);
-- break;
-+ if (conn) {
-+ int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
-+ int q = cnt / num;
-+ *quote = q ? q : 1;
-+ } else
-+ *quote = 0;
-
-- default:
-- DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-- break;
-- };
-+ BT_DBG("conn %p quote %d", conn, *quote);
-+ return conn;
- }
-
--/* Command Status OGF LINK_CTL */
--static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+static inline void hci_acl_tx_to(struct hci_dev *hdev)
- {
-- struct hci_proto * hp;
--
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- case OCF_CREATE_CONN:
-- if (status) {
-- create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
--
-- if (!cc)
-- break;
--
-- DBG("%s Create connection error: status 0x%x %s", hdev->name,
-- status, batostr(&cc->bdaddr));
-+ struct conn_hash *h = &hdev->conn_hash;
-+ struct list_head *p;
-+ struct hci_conn *c;
-
-- /* Notify upper protocols */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
-- tasklet_disable(&hdev->tx_task);
-- hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
-- tasklet_enable(&hdev->tx_task);
-- }
-- }
-- break;
-+ BT_ERR("%s ACL tx timeout", hdev->name);
-
-- case OCF_INQUIRY:
-- if (status) {
-- DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-- hci_req_complete(hdev, status);
-+ /* Kill stalled connections */
-+ list_for_each(p, &h->list) {
-+ c = list_entry(p, struct hci_conn, list);
-+ if (c->type == ACL_LINK && c->sent) {
-+ BT_ERR("%s killing stalled ACL connection %s",
-+ hdev->name, batostr(&c->dst));
-+ hci_acl_disconn(c, 0x13);
- }
-- break;
--
-- default:
-- DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Status OGF LINK_POLICY */
--static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Status OGF HOST_CTL */
--static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Status OGF INFO_PARAM */
--static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
-- DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Inquiry Complete */
--static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- __u8 status = *((__u8 *) skb->data);
--
-- DBG("%s status %d", hdev->name, status);
--
-- hci_req_complete(hdev, status);
-+ }
- }
-
--/* Inquiry Result */
--static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static inline void hci_sched_acl(struct hci_dev *hdev)
- {
-- inquiry_info *info = (inquiry_info *) (skb->data + 1);
-- int num_rsp = *((__u8 *) skb->data);
--
-- DBG("%s num_rsp %d", hdev->name, num_rsp);
-+ struct hci_conn *conn;
-+ struct sk_buff *skb;
-+ int quote;
-
-- for (; num_rsp; num_rsp--)
-- inquiry_cache_update(&hdev->inq_cache, info++);
--}
-+ BT_DBG("%s", hdev->name);
-
--/* Connect Request */
--static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- evt_conn_request *cr = (evt_conn_request *) skb->data;
-- struct hci_proto *hp;
-- accept_conn_req_cp ac;
-- int accept = 0;
-+ /* ACL tx timeout must be longer than maximum
-+ * link supervision timeout (40.9 seconds) */
-+ if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
-+ hci_acl_tx_to(hdev);
-
-- DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type);
-+ while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-+ BT_DBG("skb %p len %d", skb, skb->len);
-+ hci_send_frame(skb);
-+ hdev->acl_last_tx = jiffies;
-
-- /* Notify upper protocols */
-- if (cr->link_type == ACL_LINK) {
-- /* ACL link notify L2CAP */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
-- tasklet_disable(&hdev->tx_task);
-- accept = hp->connect_ind(hdev, &cr->bdaddr);
-- tasklet_enable(&hdev->tx_task);
-+ hdev->acl_cnt--;
-+ conn->sent++;
- }
-- } else {
-- /* SCO link (no notification) */
-- /* FIXME: Should be accept it here or let the requester (app) accept it ? */
-- accept = 1;
-- }
--
-- if (accept) {
-- /* Connection accepted by upper layer */
-- bacpy(&ac.bdaddr, &cr->bdaddr);
-- ac.role = 0x01; /* Remain slave */
-- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
-- } else {
-- /* Connection rejected by upper layer */
-- /* FIXME:
-- * Should we use HCI reject here ?
-- */
-- return;
- }
- }
-
--/* Connect Complete */
--static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+/* Schedule SCO */
-+static inline void hci_sched_sco(struct hci_dev *hdev)
- {
-- evt_conn_complete *cc = (evt_conn_complete *) skb->data;
-- struct hci_conn *conn = NULL;
-- struct hci_proto *hp;
--
-- DBG("%s", hdev->name);
--
-- tasklet_disable(&hdev->tx_task);
--
-- if (!cc->status)
-- conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr);
-+ struct hci_conn *conn;
-+ struct sk_buff *skb;
-+ int quote;
-
-- /* Notify upper protocols */
-- if (cc->link_type == ACL_LINK) {
-- /* ACL link notify L2CAP layer */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
-- hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
-- } else {
-- /* SCO link (no notification) */
-- }
-+ BT_DBG("%s", hdev->name);
-
-- tasklet_enable(&hdev->tx_task);
--}
-+ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
-+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-+ BT_DBG("skb %p len %d", skb, skb->len);
-+ hci_send_frame(skb);
-
--/* Disconnect Complete */
--static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
-- struct hci_conn *conn = NULL;
-- struct hci_proto *hp;
-- __u16 handle = __le16_to_cpu(dc->handle);
--
-- DBG("%s", hdev->name);
--
-- if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
-- tasklet_disable(&hdev->tx_task);
--
-- /* Notify upper protocols */
-- if (conn->type == ACL_LINK) {
-- /* ACL link notify L2CAP layer */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
-- hp->disconn_ind(conn, dc->reason);
-- } else {
-- /* SCO link (no notification) */
-+ conn->sent++;
-+ if (conn->sent == ~0)
-+ conn->sent = 0;
- }
--
-- hci_conn_del(hdev, conn);
--
-- tasklet_enable(&hdev->tx_task);
- }
- }
-
--/* Number of completed packets */
--static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static void hci_tx_task(unsigned long arg)
- {
-- evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
-- __u16 *ptr;
-- int i;
--
-- skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
--
-- DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-+ struct hci_dev *hdev = (struct hci_dev *) arg;
-+ struct sk_buff *skb;
-
-- if (skb->len < nc->num_hndl * 4) {
-- DBG("%s bad parameters", hdev->name);
-- return;
-- }
-+ read_lock(&hci_task_lock);
-
-- tasklet_disable(&hdev->tx_task);
-+ BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
-
-- for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
-- struct hci_conn *conn;
-- __u16 handle, count;
-+ /* Schedule queues and send stuff to HCI driver */
-
-- handle = __le16_to_cpu(get_unaligned(ptr++));
-- count = __le16_to_cpu(get_unaligned(ptr++));
-+ hci_sched_acl(hdev);
-
-- hdev->acl_cnt += count;
-+ hci_sched_sco(hdev);
-
-- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
-- conn->sent -= count;
-- }
-+ /* Send next queued raw (unknown type) packet */
-+ while ((skb = skb_dequeue(&hdev->raw_q)))
-+ hci_send_frame(skb);
-
-- tasklet_enable(&hdev->tx_task);
--
-- hci_sched_tx(hdev);
-+ read_unlock(&hci_task_lock);
- }
-
--static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- hci_event_hdr *he = (hci_event_hdr *) skb->data;
-- evt_cmd_status *cs;
-- evt_cmd_complete *ec;
-- __u16 opcode, ocf, ogf;
--
-- skb_pull(skb, HCI_EVENT_HDR_SIZE);
--
-- DBG("%s evt 0x%x", hdev->name, he->evt);
--
-- switch (he->evt) {
-- case EVT_NUM_COMP_PKTS:
-- hci_num_comp_pkts_evt(hdev, skb);
-- break;
--
-- case EVT_INQUIRY_COMPLETE:
-- hci_inquiry_complete_evt(hdev, skb);
-- break;
-
-- case EVT_INQUIRY_RESULT:
-- hci_inquiry_result_evt(hdev, skb);
-- break;
--
-- case EVT_CONN_REQUEST:
-- hci_conn_request_evt(hdev, skb);
-- break;
--
-- case EVT_CONN_COMPLETE:
-- hci_conn_complete_evt(hdev, skb);
-- break;
--
-- case EVT_DISCONN_COMPLETE:
-- hci_disconn_complete_evt(hdev, skb);
-- break;
--
-- case EVT_CMD_STATUS:
-- cs = (evt_cmd_status *) skb->data;
-- skb_pull(skb, EVT_CMD_STATUS_SIZE);
--
-- opcode = __le16_to_cpu(cs->opcode);
-- ogf = cmd_opcode_ogf(opcode);
-- ocf = cmd_opcode_ocf(opcode);
--
-- switch (ogf) {
-- case OGF_INFO_PARAM:
-- hci_cs_info_param(hdev, ocf, cs->status);
-- break;
--
-- case OGF_HOST_CTL:
-- hci_cs_host_ctl(hdev, ocf, cs->status);
-- break;
--
-- case OGF_LINK_CTL:
-- hci_cs_link_ctl(hdev, ocf, cs->status);
-- break;
--
-- case OGF_LINK_POLICY:
-- hci_cs_link_policy(hdev, ocf, cs->status);
-- break;
--
-- default:
-- DBG("%s Command Status OGF %x", hdev->name, ogf);
-- break;
-- };
--
-- if (cs->ncmd) {
-- atomic_set(&hdev->cmd_cnt, 1);
-- if (!skb_queue_empty(&hdev->cmd_q))
-- hci_sched_cmd(hdev);
-- }
-- break;
--
-- case EVT_CMD_COMPLETE:
-- ec = (evt_cmd_complete *) skb->data;
-- skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
--
-- opcode = __le16_to_cpu(ec->opcode);
-- ogf = cmd_opcode_ogf(opcode);
-- ocf = cmd_opcode_ocf(opcode);
--
-- switch (ogf) {
-- case OGF_INFO_PARAM:
-- hci_cc_info_param(hdev, ocf, skb);
-- break;
--
-- case OGF_HOST_CTL:
-- hci_cc_host_ctl(hdev, ocf, skb);
-- break;
--
-- case OGF_LINK_CTL:
-- hci_cc_link_ctl(hdev, ocf, skb);
-- break;
--
-- case OGF_LINK_POLICY:
-- hci_cc_link_policy(hdev, ocf, skb);
-- break;
--
-- default:
-- DBG("%s Command Completed OGF %x", hdev->name, ogf);
-- break;
-- };
--
-- if (ec->ncmd) {
-- atomic_set(&hdev->cmd_cnt, 1);
-- if (!skb_queue_empty(&hdev->cmd_q))
-- hci_sched_cmd(hdev);
-- }
-- break;
-- };
--
-- kfree_skb(skb);
-- hdev->stat.evt_rx++;
--}
-+/* ----- HCI RX task (incomming data proccessing) ----- */
-
- /* ACL data packet */
- static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-@@ -1867,51 +1255,86 @@
- flags = acl_flags(handle);
- handle = acl_handle(handle);
-
-- DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-+ BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-+
-+ hdev->stat.acl_rx++;
-
-- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
-+ hci_dev_lock(hdev);
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ hci_dev_unlock(hdev);
-+
-+ if (conn) {
- register struct hci_proto *hp;
-
- /* Send to upper protocol */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) {
-+ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
- hp->recv_acldata(conn, skb, flags);
-- goto sent;
-+ return;
- }
- } else {
-- ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle);
-+ BT_ERR("%s ACL packet for unknown connection handle %d",
-+ hdev->name, handle);
- }
-
- kfree_skb(skb);
--sent:
-- hdev->stat.acl_rx++;
- }
-
- /* SCO data packet */
- static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
- {
-- DBG("%s len %d", hdev->name, skb->len);
-+ hci_sco_hdr *sh = (void *) skb->data;
-+ struct hci_conn *conn;
-+ __u16 handle;
-+
-+ skb_pull(skb, HCI_SCO_HDR_SIZE);
-+
-+ handle = __le16_to_cpu(sh->handle);
-+
-+ BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
-
-- kfree_skb(skb);
- hdev->stat.sco_rx++;
-+
-+ hci_dev_lock(hdev);
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ hci_dev_unlock(hdev);
-+
-+ if (conn) {
-+ register struct hci_proto *hp;
-+
-+ /* Send to upper protocol */
-+ if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
-+ hp->recv_scodata(conn, skb);
-+ return;
-+ }
-+ } else {
-+ BT_ERR("%s SCO packet for unknown connection handle %d",
-+ hdev->name, handle);
-+ }
-+
-+ kfree_skb(skb);
- }
-
--/* ----- HCI tasks ----- */
- void hci_rx_task(unsigned long arg)
- {
- struct hci_dev *hdev = (struct hci_dev *) arg;
- struct sk_buff *skb;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s", hdev->name);
-
- read_lock(&hci_task_lock);
-
- while ((skb = skb_dequeue(&hdev->rx_q))) {
-- if (hdev->flags & HCI_SOCK) {
-+ if (atomic_read(&hdev->promisc)) {
- /* Send copy to the sockets */
- hci_send_to_sock(hdev, skb);
- }
-
-- if (hdev->flags & HCI_INIT) {
-+ if (test_bit(HCI_RAW, &hdev->flags)) {
-+ kfree_skb(skb);
-+ continue;
-+ }
-+
-+ if (test_bit(HCI_INIT, &hdev->flags)) {
- /* Don't process data packets in this states. */
- switch (skb->pkt_type) {
- case HCI_ACLDATA_PKT:
-@@ -1921,64 +1344,43 @@
- };
- }
-
-- if (hdev->flags & HCI_NORMAL) {
-- /* Process frame */
-- switch (skb->pkt_type) {
-- case HCI_EVENT_PKT:
-- hci_event_packet(hdev, skb);
-- break;
-+ /* Process frame */
-+ switch (skb->pkt_type) {
-+ case HCI_EVENT_PKT:
-+ hci_event_packet(hdev, skb);
-+ break;
-
-- case HCI_ACLDATA_PKT:
-- DBG("%s ACL data packet", hdev->name);
-- hci_acldata_packet(hdev, skb);
-- break;
-+ case HCI_ACLDATA_PKT:
-+ BT_DBG("%s ACL data packet", hdev->name);
-+ hci_acldata_packet(hdev, skb);
-+ break;
-
-- case HCI_SCODATA_PKT:
-- DBG("%s SCO data packet", hdev->name);
-- hci_scodata_packet(hdev, skb);
-- break;
-+ case HCI_SCODATA_PKT:
-+ BT_DBG("%s SCO data packet", hdev->name);
-+ hci_scodata_packet(hdev, skb);
-+ break;
-
-- default:
-- kfree_skb(skb);
-- break;
-- };
-- } else {
-+ default:
- kfree_skb(skb);
-+ break;
- }
- }
-
- read_unlock(&hci_task_lock);
- }
-
--static void hci_tx_task(unsigned long arg)
--{
-- struct hci_dev *hdev = (struct hci_dev *) arg;
-- struct sk_buff *skb;
--
-- read_lock(&hci_task_lock);
--
-- DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
--
-- /* Schedule queues and send stuff to HCI driver */
--
-- hci_sched_acl(hdev);
--
-- hci_sched_sco(hdev);
--
-- /* Send next queued raw (unknown type) packet */
-- while ((skb = skb_dequeue(&hdev->raw_q)))
-- hci_send_frame(skb);
--
-- read_unlock(&hci_task_lock);
--}
--
- static void hci_cmd_task(unsigned long arg)
- {
- struct hci_dev *hdev = (struct hci_dev *) arg;
- struct sk_buff *skb;
-
-- DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-+ BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-
-+ if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
-+ BT_ERR("%s command tx timeout", hdev->name);
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ }
-+
- /* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
- if (hdev->sent_cmd)
-@@ -1987,6 +1389,7 @@
- if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
- atomic_dec(&hdev->cmd_cnt);
- hci_send_frame(skb);
-+ hdev->cmd_last_tx = jiffies;
- } else {
- skb_queue_head(&hdev->cmd_q, skb);
- hci_sched_cmd(hdev);
-@@ -1994,33 +1397,10 @@
- }
- }
-
--/* Receive frame from HCI drivers */
--int hci_recv_frame(struct sk_buff *skb)
--{
-- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--
-- if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
-- kfree_skb(skb);
-- return -1;
-- }
--
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
-- /* Incomming skb */
-- bluez_cb(skb)->incomming = 1;
--
-- /* Queue frame for rx task */
-- skb_queue_tail(&hdev->rx_q, skb);
-- hci_sched_rx(hdev);
--
-- return 0;
--}
-+/* ---- Initialization ---- */
-
- int hci_core_init(void)
- {
-- /* Init locks */
-- spin_lock_init(&hdev_list_lock);
--
- return 0;
- }
-
-@@ -2028,5 +1408,3 @@
- {
- return 0;
- }
--
--MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/hci_event.c linux-2.4.18-mh15/net/bluetooth/hci_event.c
---- linux-2.4.18/net/bluetooth/hci_event.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hci_event.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,910 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * HCI Events.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/notifier.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef HCI_CORE_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+/* Handle HCI Event packets */
-+
-+/* Command Complete OGF LINK_CTL */
-+static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ __u8 status;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_INQUIRY_CANCEL:
-+ status = *((__u8 *) skb->data);
-+
-+ if (status) {
-+ BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
-+ } else {
-+ clear_bit(HCI_INQUIRY, &hdev->flags);
-+ hci_req_complete(hdev, status);
-+ }
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Complete OGF LINK_POLICY */
-+static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ struct hci_conn *conn;
-+ role_discovery_rp *rd;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_ROLE_DISCOVERY:
-+ rd = (void *) skb->data;
-+
-+ if (rd->status)
-+ break;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
-+ if (conn) {
-+ if (rd->role)
-+ conn->link_mode &= ~HCI_LM_MASTER;
-+ else
-+ conn->link_mode |= HCI_LM_MASTER;
-+ }
-+
-+ hci_dev_unlock(hdev);
-+ break;
-+
-+ default:
-+ BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
-+ hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Complete OGF HOST_CTL */
-+static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ __u8 status, param;
-+ void *sent;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_RESET:
-+ status = *((__u8 *) skb->data);
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_SET_EVENT_FLT:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-+ } else {
-+ BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-+ }
-+ break;
-+
-+ case OCF_WRITE_AUTH_ENABLE:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
-+ if (!sent)
-+ break;
-+
-+ status = *((__u8 *) skb->data);
-+ param = *((__u8 *) sent);
-+
-+ if (!status) {
-+ if (param == AUTH_ENABLED)
-+ set_bit(HCI_AUTH, &hdev->flags);
-+ else
-+ clear_bit(HCI_AUTH, &hdev->flags);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_WRITE_ENCRYPT_MODE:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
-+ if (!sent)
-+ break;
-+
-+ status = *((__u8 *) skb->data);
-+ param = *((__u8 *) sent);
-+
-+ if (!status) {
-+ if (param)
-+ set_bit(HCI_ENCRYPT, &hdev->flags);
-+ else
-+ clear_bit(HCI_ENCRYPT, &hdev->flags);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_WRITE_CA_TIMEOUT:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-+ } else {
-+ BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-+ }
-+ break;
-+
-+ case OCF_WRITE_PG_TIMEOUT:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-+ } else {
-+ BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-+ }
-+ break;
-+
-+ case OCF_WRITE_SCAN_ENABLE:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
-+ if (!sent)
-+ break;
-+ status = *((__u8 *) skb->data);
-+ param = *((__u8 *) sent);
-+
-+ BT_DBG("param 0x%x", param);
-+
-+ if (!status) {
-+ clear_bit(HCI_PSCAN, &hdev->flags);
-+ clear_bit(HCI_ISCAN, &hdev->flags);
-+ if (param & SCAN_INQUIRY)
-+ set_bit(HCI_ISCAN, &hdev->flags);
-+
-+ if (param & SCAN_PAGE)
-+ set_bit(HCI_PSCAN, &hdev->flags);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_HOST_BUFFER_SIZE:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
-+ hci_req_complete(hdev, status);
-+ }
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Complete OGF INFO_PARAM */
-+static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ read_local_features_rp *lf;
-+ read_buffer_size_rp *bs;
-+ read_bd_addr_rp *ba;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_READ_LOCAL_FEATURES:
-+ lf = (read_local_features_rp *) skb->data;
-+
-+ if (lf->status) {
-+ BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-+ break;
-+ }
-+
-+ memcpy(hdev->features, lf->features, sizeof(hdev->features));
-+
-+ /* Adjust default settings according to features
-+ * supported by device. */
-+ if (hdev->features[0] & LMP_3SLOT)
-+ hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-+
-+ if (hdev->features[0] & LMP_5SLOT)
-+ hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-+
-+ if (hdev->features[1] & LMP_HV2)
-+ hdev->pkt_type |= (HCI_HV2);
-+
-+ if (hdev->features[1] & LMP_HV3)
-+ hdev->pkt_type |= (HCI_HV3);
-+
-+ BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
-+
-+ break;
-+
-+ case OCF_READ_BUFFER_SIZE:
-+ bs = (read_buffer_size_rp *) skb->data;
-+
-+ if (bs->status) {
-+ BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-+ hci_req_complete(hdev, bs->status);
-+ break;
-+ }
-+
-+ hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
-+ hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64;
-+ hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-+ hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
-+
-+ BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-+ hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
-+ break;
-+
-+ case OCF_READ_BD_ADDR:
-+ ba = (read_bd_addr_rp *) skb->data;
-+
-+ if (!ba->status) {
-+ bacpy(&hdev->bdaddr, &ba->bdaddr);
-+ } else {
-+ BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-+ }
-+
-+ hci_req_complete(hdev, ba->status);
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF LINK_CTL */
-+static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
-+{
-+ struct hci_conn *conn;
-+ create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
-+
-+ if (!cc)
-+ return;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr);
-+
-+ BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
-+ status, batostr(&cc->bdaddr), conn);
-+
-+ if (status) {
-+ if (conn && conn->state == BT_CONNECT) {
-+ conn->state = BT_CLOSED;
-+ hci_proto_connect_cfm(conn, status);
-+ hci_conn_del(conn);
-+ }
-+ } else {
-+ if (!conn) {
-+ conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr);
-+ if (conn) {
-+ conn->out = 1;
-+ conn->link_mode |= HCI_LM_MASTER;
-+ } else
-+ BT_ERR("No memmory for new connection");
-+ }
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_CREATE_CONN:
-+ hci_cs_create_conn(hdev, status);
-+ break;
-+
-+ case OCF_ADD_SCO:
-+ if (status) {
-+ struct hci_conn *acl, *sco;
-+ add_sco_cp *cp = hci_sent_cmd_data(hdev,
-+ OGF_LINK_CTL, OCF_ADD_SCO);
-+ __u16 handle;
-+
-+ if (!cp)
-+ break;
-+
-+ handle = __le16_to_cpu(cp->handle);
-+
-+ BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
-+
-+ hci_dev_lock(hdev);
-+
-+ acl = conn_hash_lookup_handle(hdev, handle);
-+ if (acl && (sco = acl->link)) {
-+ sco->state = BT_CLOSED;
-+ hci_proto_connect_cfm(sco, status);
-+ hci_conn_del(sco);
-+ }
-+
-+ hci_dev_unlock(hdev);
-+ }
-+ break;
-+
-+ case OCF_INQUIRY:
-+ if (status) {
-+ BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-+ hci_req_complete(hdev, status);
-+ } else {
-+ set_bit(HCI_INQUIRY, &hdev->flags);
-+ }
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d",
-+ hdev->name, ocf, status);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF LINK_POLICY */
-+static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ default:
-+ BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF HOST_CTL */
-+static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ default:
-+ BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF INFO_PARAM */
-+static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ default:
-+ BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Inquiry Complete */
-+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ __u8 status = *((__u8 *) skb->data);
-+
-+ BT_DBG("%s status %d", hdev->name, status);
-+
-+ clear_bit(HCI_INQUIRY, &hdev->flags);
-+ hci_req_complete(hdev, status);
-+}
-+
-+/* Inquiry Result */
-+static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ inquiry_info *info = (inquiry_info *) (skb->data + 1);
-+ int num_rsp = *((__u8 *) skb->data);
-+
-+ BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-+
-+ hci_dev_lock(hdev);
-+ for (; num_rsp; num_rsp--)
-+ inquiry_cache_update(hdev, info++);
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Inquiry Result With RSSI */
-+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ inquiry_info_with_rssi *info = (inquiry_info_with_rssi *) (skb->data + 1);
-+ int num_rsp = *((__u8 *) skb->data);
-+
-+ BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-+
-+ hci_dev_lock(hdev);
-+ for (; num_rsp; num_rsp--) {
-+ inquiry_info tmp;
-+ bacpy(&tmp.bdaddr, &info->bdaddr);
-+ tmp.pscan_rep_mode = info->pscan_rep_mode;
-+ tmp.pscan_period_mode = info->pscan_period_mode;
-+ tmp.pscan_mode = 0x00;
-+ memcpy(tmp.dev_class, &info->dev_class, 3);
-+ tmp.clock_offset = info->clock_offset;
-+ info++;
-+ inquiry_cache_update(hdev, &tmp);
-+ }
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Connect Request */
-+static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_conn_request *cr = (evt_conn_request *) skb->data;
-+ int mask = hdev->link_mode;
-+
-+ BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
-+ batostr(&cr->bdaddr), cr->link_type);
-+
-+ mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type);
-+
-+ if (mask & HCI_LM_ACCEPT) {
-+ /* Connection accepted */
-+ struct hci_conn *conn;
-+ accept_conn_req_cp ac;
-+
-+ hci_dev_lock(hdev);
-+ conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr);
-+ if (!conn) {
-+ if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) {
-+ BT_ERR("No memmory for new connection");
-+ hci_dev_unlock(hdev);
-+ return;
-+ }
-+ }
-+ conn->state = BT_CONNECT;
-+ hci_dev_unlock(hdev);
-+
-+ bacpy(&ac.bdaddr, &cr->bdaddr);
-+
-+ if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
-+ ac.role = 0x00; /* Become master */
-+ else
-+ ac.role = 0x01; /* Remain slave */
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ,
-+ ACCEPT_CONN_REQ_CP_SIZE, &ac);
-+ } else {
-+ /* Connection rejected */
-+ reject_conn_req_cp rc;
-+
-+ bacpy(&rc.bdaddr, &cr->bdaddr);
-+ rc.reason = 0x0f;
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ,
-+ REJECT_CONN_REQ_CP_SIZE, &rc);
-+ }
-+}
-+
-+/* Connect Complete */
-+static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_conn_complete *cc = (evt_conn_complete *) skb->data;
-+ struct hci_conn *conn = NULL;
-+
-+ BT_DBG("%s", hdev->name);
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
-+ if (!conn) {
-+ hci_dev_unlock(hdev);
-+ return;
-+ }
-+
-+ if (!cc->status) {
-+ conn->handle = __le16_to_cpu(cc->handle);
-+ conn->state = BT_CONNECTED;
-+
-+ if (test_bit(HCI_AUTH, &hdev->flags))
-+ conn->link_mode |= HCI_LM_AUTH;
-+
-+ if (test_bit(HCI_ENCRYPT, &hdev->flags))
-+ conn->link_mode |= HCI_LM_ENCRYPT;
-+
-+
-+ /* Set link policy */
-+ if (conn->type == ACL_LINK && hdev->link_policy) {
-+ write_link_policy_cp lp;
-+ lp.handle = cc->handle;
-+ lp.policy = __cpu_to_le16(hdev->link_policy);
-+ hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
-+ WRITE_LINK_POLICY_CP_SIZE, &lp);
-+ }
-+
-+ /* Set packet type for incomming connection */
-+ if (!conn->out) {
-+ change_conn_ptype_cp cp;
-+ cp.handle = cc->handle;
-+ cp.pkt_type = (conn->type == ACL_LINK) ?
-+ __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
-+ __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE,
-+ CHANGE_CONN_PTYPE_CP_SIZE, &cp);
-+ }
-+ } else
-+ conn->state = BT_CLOSED;
-+
-+ if (conn->type == ACL_LINK) {
-+ struct hci_conn *sco = conn->link;
-+ if (sco) {
-+ if (!cc->status)
-+ hci_add_sco(sco, conn->handle);
-+ else {
-+ hci_proto_connect_cfm(sco, cc->status);
-+ hci_conn_del(sco);
-+ }
-+ }
-+ }
-+
-+ hci_proto_connect_cfm(conn, cc->status);
-+ if (cc->status)
-+ hci_conn_del(conn);
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Disconnect Complete */
-+static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
-+ struct hci_conn *conn = NULL;
-+ __u16 handle = __le16_to_cpu(dc->handle);
-+
-+ BT_DBG("%s status %d", hdev->name, dc->status);
-+
-+ if (dc->status)
-+ return;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ conn->state = BT_CLOSED;
-+ hci_proto_disconn_ind(conn, dc->reason);
-+ hci_conn_del(conn);
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Number of completed packets */
-+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
-+ __u16 *ptr;
-+ int i;
-+
-+ skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
-+
-+ BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-+
-+ if (skb->len < nc->num_hndl * 4) {
-+ BT_DBG("%s bad parameters", hdev->name);
-+ return;
-+ }
-+
-+ tasklet_disable(&hdev->tx_task);
-+
-+ for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
-+ struct hci_conn *conn;
-+ __u16 handle, count;
-+
-+ handle = __le16_to_cpu(get_unaligned(ptr++));
-+ count = __le16_to_cpu(get_unaligned(ptr++));
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ conn->sent -= count;
-+
-+ if (conn->type == SCO_LINK) {
-+ if ((hdev->sco_cnt += count) > hdev->sco_pkts)
-+ hdev->sco_cnt = hdev->sco_pkts;
-+ } else {
-+ if ((hdev->acl_cnt += count) > hdev->acl_pkts)
-+ hdev->acl_cnt = hdev->acl_pkts;
-+ }
-+ }
-+ }
-+ hci_sched_tx(hdev);
-+
-+ tasklet_enable(&hdev->tx_task);
-+}
-+
-+/* Role Change */
-+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_role_change *rc = (evt_role_change *) skb->data;
-+ struct hci_conn *conn = NULL;
-+
-+ BT_DBG("%s status %d", hdev->name, rc->status);
-+
-+ if (rc->status)
-+ return;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
-+ if (conn) {
-+ if (rc->role)
-+ conn->link_mode &= ~HCI_LM_MASTER;
-+ else
-+ conn->link_mode |= HCI_LM_MASTER;
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Authentication Complete */
-+static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_auth_complete *ac = (evt_auth_complete *) skb->data;
-+ struct hci_conn *conn = NULL;
-+ __u16 handle = __le16_to_cpu(ac->handle);
-+
-+ BT_DBG("%s status %d", hdev->name, ac->status);
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ if (!ac->status)
-+ conn->link_mode |= HCI_LM_AUTH;
-+ clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-+
-+ hci_proto_auth_cfm(conn, ac->status);
-+
-+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
-+ if (!ac->status) {
-+ set_conn_encrypt_cp ce;
-+ ce.handle = __cpu_to_le16(conn->handle);
-+ ce.encrypt = 1;
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-+ OCF_SET_CONN_ENCRYPT,
-+ SET_CONN_ENCRYPT_CP_SIZE, &ce);
-+ } else {
-+ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-+ hci_proto_encrypt_cfm(conn, ac->status);
-+ }
-+ }
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Encryption Change */
-+static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_encrypt_change *ec = (evt_encrypt_change *) skb->data;
-+ struct hci_conn *conn = NULL;
-+ __u16 handle = __le16_to_cpu(ec->handle);
-+
-+ BT_DBG("%s status %d", hdev->name, ec->status);
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ if (!ec->status) {
-+ if (ec->encrypt)
-+ conn->link_mode |= HCI_LM_ENCRYPT;
-+ else
-+ conn->link_mode &= ~HCI_LM_ENCRYPT;
-+ }
-+ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-+
-+ hci_proto_encrypt_cfm(conn, ec->status);
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ hci_event_hdr *he = (hci_event_hdr *) skb->data;
-+ evt_cmd_status *cs;
-+ evt_cmd_complete *ec;
-+ __u16 opcode, ocf, ogf;
-+
-+ skb_pull(skb, HCI_EVENT_HDR_SIZE);
-+
-+ BT_DBG("%s evt 0x%x", hdev->name, he->evt);
-+
-+ switch (he->evt) {
-+ case EVT_NUM_COMP_PKTS:
-+ hci_num_comp_pkts_evt(hdev, skb);
-+ break;
-+
-+ case EVT_INQUIRY_COMPLETE:
-+ hci_inquiry_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_INQUIRY_RESULT:
-+ hci_inquiry_result_evt(hdev, skb);
-+ break;
-+
-+ case EVT_INQUIRY_RESULT_WITH_RSSI:
-+ hci_inquiry_result_with_rssi_evt(hdev, skb);
-+ break;
-+
-+ case EVT_CONN_REQUEST:
-+ hci_conn_request_evt(hdev, skb);
-+ break;
-+
-+ case EVT_CONN_COMPLETE:
-+ hci_conn_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_DISCONN_COMPLETE:
-+ hci_disconn_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_ROLE_CHANGE:
-+ hci_role_change_evt(hdev, skb);
-+ break;
-+
-+ case EVT_AUTH_COMPLETE:
-+ hci_auth_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_ENCRYPT_CHANGE:
-+ hci_encrypt_change_evt(hdev, skb);
-+ break;
-+
-+ case EVT_CMD_STATUS:
-+ cs = (evt_cmd_status *) skb->data;
-+ skb_pull(skb, EVT_CMD_STATUS_SIZE);
-+
-+ opcode = __le16_to_cpu(cs->opcode);
-+ ogf = cmd_opcode_ogf(opcode);
-+ ocf = cmd_opcode_ocf(opcode);
-+
-+ switch (ogf) {
-+ case OGF_INFO_PARAM:
-+ hci_cs_info_param(hdev, ocf, cs->status);
-+ break;
-+
-+ case OGF_HOST_CTL:
-+ hci_cs_host_ctl(hdev, ocf, cs->status);
-+ break;
-+
-+ case OGF_LINK_CTL:
-+ hci_cs_link_ctl(hdev, ocf, cs->status);
-+ break;
-+
-+ case OGF_LINK_POLICY:
-+ hci_cs_link_policy(hdev, ocf, cs->status);
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
-+ break;
-+ };
-+
-+ if (cs->ncmd) {
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ if (!skb_queue_empty(&hdev->cmd_q))
-+ hci_sched_cmd(hdev);
-+ }
-+ break;
-+
-+ case EVT_CMD_COMPLETE:
-+ ec = (evt_cmd_complete *) skb->data;
-+ skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
-+
-+ opcode = __le16_to_cpu(ec->opcode);
-+ ogf = cmd_opcode_ogf(opcode);
-+ ocf = cmd_opcode_ocf(opcode);
-+
-+ switch (ogf) {
-+ case OGF_INFO_PARAM:
-+ hci_cc_info_param(hdev, ocf, skb);
-+ break;
-+
-+ case OGF_HOST_CTL:
-+ hci_cc_host_ctl(hdev, ocf, skb);
-+ break;
-+
-+ case OGF_LINK_CTL:
-+ hci_cc_link_ctl(hdev, ocf, skb);
-+ break;
-+
-+ case OGF_LINK_POLICY:
-+ hci_cc_link_policy(hdev, ocf, skb);
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
-+ break;
-+ };
-+
-+ if (ec->ncmd) {
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ if (!skb_queue_empty(&hdev->cmd_q))
-+ hci_sched_cmd(hdev);
-+ }
-+ break;
-+ };
-+
-+ kfree_skb(skb);
-+ hdev->stat.evt_rx++;
-+}
-+
-+/* General internal stack event */
-+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-+{
-+ hci_event_hdr *eh;
-+ evt_stack_internal *si;
-+ struct sk_buff *skb;
-+ int size;
-+ void *ptr;
-+
-+ size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
-+ skb = bluez_skb_alloc(size, GFP_ATOMIC);
-+ if (!skb)
-+ return;
-+
-+ ptr = skb_put(skb, size);
-+
-+ eh = ptr;
-+ eh->evt = EVT_STACK_INTERNAL;
-+ eh->plen = EVT_STACK_INTERNAL_SIZE + dlen;
-+ ptr += HCI_EVENT_HDR_SIZE;
-+
-+ si = ptr;
-+ si->type = type;
-+ memcpy(si->data, data, dlen);
-+
-+ skb->pkt_type = HCI_EVENT_PKT;
-+ skb->dev = (void *) hdev;
-+ hci_send_to_sock(hdev, skb);
-+ kfree_skb(skb);
-+}
-diff -urN linux-2.4.18/net/bluetooth/hci_sock.c linux-2.4.18-mh15/net/bluetooth/hci_sock.c
---- linux-2.4.18/net/bluetooth/hci_sock.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/hci_sock.c 2004-08-01 16:26:23.000000000 +0200
-@@ -25,7 +25,7 @@
- /*
- * BlueZ HCI socket layer.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
-@@ -49,45 +49,54 @@
-
- #include <asm/system.h>
- #include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
-
- #ifndef HCI_SOCK_DEBUG
--#undef DBG
--#define DBG( A... )
-+#undef BT_DBG
-+#define BT_DBG( A... )
- #endif
-
--/* HCI socket interface */
-+/* ----- HCI socket interface ----- */
-+
-+/* Security filter */
-+static struct hci_sec_filter hci_sec_filter = {
-+ /* Packet types */
-+ 0x10,
-+ /* Events */
-+ { 0x1000d9fe, 0x0000300c },
-+ /* Commands */
-+ {
-+ { 0x0 },
-+ /* OGF_LINK_CTL */
-+ { 0xbe000006, 0x00000001, 0x0000, 0x00 },
-+ /* OGF_LINK_POLICY */
-+ { 0x00005200, 0x00000000, 0x0000, 0x00 },
-+ /* OGF_HOST_CTL */
-+ { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 },
-+ /* OGF_INFO_PARAM */
-+ { 0x000002be, 0x00000000, 0x0000, 0x00 },
-+ /* OGF_STATUS_PARAM */
-+ { 0x000000ea, 0x00000000, 0x0000, 0x00 }
-+ }
-+};
-
- static struct bluez_sock_list hci_sk_list = {
- lock: RW_LOCK_UNLOCKED
- };
-
--static struct sock *hci_sock_lookup(struct hci_dev *hdev)
--{
-- struct sock *sk;
--
-- read_lock(&hci_sk_list.lock);
-- for (sk = hci_sk_list.head; sk; sk = sk->next) {
-- if (hci_pi(sk)->hdev == hdev)
-- break;
-- }
-- read_unlock(&hci_sk_list.lock);
-- return sk;
--}
--
- /* Send frame to RAW socket */
- void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct sock * sk;
-
-- DBG("hdev %p len %d", hdev, skb->len);
-+ BT_DBG("hdev %p len %d", hdev, skb->len);
-
- read_lock(&hci_sk_list.lock);
- for (sk = hci_sk_list.head; sk; sk = sk->next) {
-- struct hci_filter *flt;
-+ struct hci_filter *flt;
- struct sk_buff *nskb;
-
- if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
-@@ -100,13 +109,19 @@
- /* Apply filter */
- flt = &hci_pi(sk)->filter;
-
-- if (!test_bit(skb->pkt_type, &flt->type_mask))
-+ if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
- continue;
-
- if (skb->pkt_type == HCI_EVENT_PKT) {
-- register int evt = (*(__u8 *)skb->data & 63);
-+ register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
-+
-+ if (!hci_test_bit(evt, &flt->event_mask))
-+ continue;
-
-- if (!test_bit(evt, &flt->event_mask))
-+ if (flt->opcode && ((evt == EVT_CMD_COMPLETE &&
-+ flt->opcode != *(__u16 *)(skb->data + 3)) ||
-+ (evt == EVT_CMD_STATUS &&
-+ flt->opcode != *(__u16 *)(skb->data + 4))))
- continue;
- }
-
-@@ -116,8 +131,8 @@
- /* Put type byte before the data */
- memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
-
-- skb_queue_tail(&sk->receive_queue, nskb);
-- sk->data_ready(sk, nskb->len);
-+ if (sock_queue_rcv_skb(sk, nskb))
-+ kfree_skb(nskb);
- }
- read_unlock(&hci_sk_list.lock);
- }
-@@ -127,7 +142,7 @@
- struct sock *sk = sock->sk;
- struct hci_dev *hdev = hci_pi(sk)->hdev;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-@@ -135,9 +150,7 @@
- bluez_sock_unlink(&hci_sk_list, sk);
-
- if (hdev) {
-- if (!hci_sock_lookup(hdev))
-- hdev->flags &= ~HCI_SOCK;
--
-+ atomic_dec(&hdev->promisc);
- hci_dev_put(hdev);
- }
-
-@@ -149,24 +162,55 @@
- sock_put(sk);
-
- MOD_DEC_USE_COUNT;
--
- return 0;
- }
-
--static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+/* Ioctls that require bound socket */
-+static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
- {
-- struct sock *sk = sock->sk;
- struct hci_dev *hdev = hci_pi(sk)->hdev;
-- __u32 mode;
-
-- DBG("cmd %x arg %lx", cmd, arg);
-+ if (!hdev)
-+ return -EBADFD;
-
- switch (cmd) {
-- case HCIGETINFO:
-- return hci_dev_info(arg);
-+ case HCISETRAW:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-
-+ if (arg)
-+ set_bit(HCI_RAW, &hdev->flags);
-+ else
-+ clear_bit(HCI_RAW, &hdev->flags);
-+
-+ return 0;
-+
-+ case HCIGETCONNINFO:
-+ return hci_get_conn_info(hdev, arg);
-+
-+ default:
-+ if (hdev->ioctl)
-+ return hdev->ioctl(hdev, cmd, arg);
-+ return -EINVAL;
-+ }
-+}
-+
-+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct sock *sk = sock->sk;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
- case HCIGETDEVLIST:
-- return hci_dev_list(arg);
-+ return hci_get_dev_list(arg);
-+
-+ case HCIGETDEVINFO:
-+ return hci_get_dev_info(arg);
-+
-+ case HCIGETCONNLIST:
-+ return hci_get_conn_list(arg);
-
- case HCIDEVUP:
- if (!capable(CAP_NET_ADMIN))
-@@ -183,48 +227,31 @@
- return -EACCES;
- return hci_dev_reset(arg);
-
-- case HCIRESETSTAT:
-+ case HCIDEVRESTAT:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_reset_stat(arg);
-
- case HCISETSCAN:
-- if (!capable(CAP_NET_ADMIN))
-- return -EACCES;
-- return hci_dev_setscan(arg);
--
- case HCISETAUTH:
-- if (!capable(CAP_NET_ADMIN))
-- return -EACCES;
-- return hci_dev_setauth(arg);
--
-- case HCISETRAW:
-- if (!capable(CAP_NET_ADMIN))
-- return -EACCES;
--
-- if (!hdev)
-- return -EBADFD;
--
-- if (arg)
-- mode = HCI_RAW;
-- else
-- mode = HCI_NORMAL;
--
-- return hci_dev_setmode(hdev, mode);
--
-+ case HCISETENCRYPT:
- case HCISETPTYPE:
-+ case HCISETLINKPOL:
-+ case HCISETLINKMODE:
-+ case HCISETACLMTU:
-+ case HCISETSCOMTU:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-- return hci_dev_setptype(arg);
-+ return hci_dev_cmd(cmd, arg);
-
- case HCIINQUIRY:
- return hci_inquiry(arg);
-
-- case HCIGETCONNLIST:
-- return hci_conn_list(arg);
--
- default:
-- return -EINVAL;
-+ lock_sock(sk);
-+ err = hci_sock_bound_ioctl(sk, cmd, arg);
-+ release_sock(sk);
-+ return err;
- };
- }
-
-@@ -233,28 +260,35 @@
- struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
- struct sock *sk = sock->sk;
- struct hci_dev *hdev = NULL;
-+ int err = 0;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p sk %p", sock, sk);
-
- if (!haddr || haddr->hci_family != AF_BLUETOOTH)
- return -EINVAL;
-
-+ lock_sock(sk);
-+
- if (hci_pi(sk)->hdev) {
-- /* Already bound */
-- return 0;
-+ err = -EALREADY;
-+ goto done;
- }
-
- if (haddr->hci_dev != HCI_DEV_NONE) {
-- if (!(hdev = hci_dev_get(haddr->hci_dev)))
-- return -ENODEV;
-+ if (!(hdev = hci_dev_get(haddr->hci_dev))) {
-+ err = -ENODEV;
-+ goto done;
-+ }
-
-- hdev->flags |= HCI_SOCK;
-+ atomic_inc(&hdev->promisc);
- }
-
- hci_pi(sk)->hdev = hdev;
- sk->state = BT_BOUND;
-
-- return 0;
-+done:
-+ release_sock(sk);
-+ return err;
- }
-
- static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
-@@ -262,73 +296,44 @@
- struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
- struct sock *sk = sock->sk;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ lock_sock(sk);
-
- *addr_len = sizeof(*haddr);
- haddr->hci_family = AF_BLUETOOTH;
- haddr->hci_dev = hci_pi(sk)->hdev->id;
-
-+ release_sock(sk);
- return 0;
- }
-
--static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-- struct scm_cookie *scm)
--{
-- struct sock *sk = sock->sk;
-- struct hci_dev *hdev = hci_pi(sk)->hdev;
-- struct sk_buff *skb;
-- int err;
--
-- DBG("sock %p sk %p", sock, sk);
--
-- if (msg->msg_flags & MSG_OOB)
-- return -EOPNOTSUPP;
--
-- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
-- return -EINVAL;
--
-- if (!hdev)
-- return -EBADFD;
--
-- if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
-- return err;
--
-- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
-- kfree_skb(skb);
-- return -EFAULT;
-- }
--
-- skb->dev = (void *) hdev;
-- skb->pkt_type = *((unsigned char *) skb->data);
-- skb_pull(skb, 1);
--
-- /* Send frame to HCI core */
-- hci_send_raw(skb);
--
-- return len;
--}
--
- static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
- {
- __u32 mask = hci_pi(sk)->cmsg_mask;
-
- if (mask & HCI_CMSG_DIR)
- put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
-+
-+ if (mask & HCI_CMSG_TSTAMP)
-+ put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
- }
-
--static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
-- int flags, struct scm_cookie *scm)
-+static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
- {
- int noblock = flags & MSG_DONTWAIT;
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- int copied, err;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p, sk %p", sock, sk);
-
-- if (flags & (MSG_OOB | MSG_PEEK))
-+ if (flags & (MSG_OOB))
- return -EOPNOTSUPP;
-
-+ if (sk->state == BT_CLOSED)
-+ return 0;
-+
- if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
- return err;
-
-@@ -343,28 +348,107 @@
- skb->h.raw = skb->data;
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-
-- if (hci_pi(sk)->cmsg_mask)
-- hci_sock_cmsg(sk, msg, skb);
--
-+ hci_sock_cmsg(sk, msg, skb);
-+
- skb_free_datagram(sk, skb);
-
- return err ? : copied;
- }
-
-+static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-+ struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ struct hci_dev *hdev;
-+ struct sk_buff *skb;
-+ int err;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
-+ return -EINVAL;
-+
-+ if (len < 4)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (!(hdev = hci_pi(sk)->hdev)) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
-+ goto done;
-+
-+ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
-+ err = -EFAULT;
-+ goto drop;
-+ }
-+
-+ skb->pkt_type = *((unsigned char *) skb->data);
-+ skb_pull(skb, 1);
-+ skb->dev = (void *) hdev;
-+
-+ if (skb->pkt_type == HCI_COMMAND_PKT) {
-+ u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
-+ u16 ogf = cmd_opcode_ogf(opcode);
-+ u16 ocf = cmd_opcode_ocf(opcode);
-+
-+ if (((ogf > HCI_SFLT_MAX_OGF) ||
-+ !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-+ !capable(CAP_NET_RAW)) {
-+ err = -EPERM;
-+ goto drop;
-+ }
-+
-+ if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
-+ skb_queue_tail(&hdev->raw_q, skb);
-+ hci_sched_tx(hdev);
-+ } else {
-+ skb_queue_tail(&hdev->cmd_q, skb);
-+ hci_sched_cmd(hdev);
-+ }
-+ } else {
-+ if (!capable(CAP_NET_RAW)) {
-+ err = -EPERM;
-+ goto drop;
-+ }
-+
-+ skb_queue_tail(&hdev->raw_q, skb);
-+ hci_sched_tx(hdev);
-+ }
-+
-+ err = len;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+
-+drop:
-+ kfree_skb(skb);
-+ goto done;
-+}
-+
- int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
- {
- struct sock *sk = sock->sk;
-- struct hci_filter flt;
-+ struct hci_filter flt = { opcode: 0 };
- int err = 0, opt = 0;
-
-- DBG("sk %p, opt %d", sk, optname);
-+ BT_DBG("sk %p, opt %d", sk, optname);
-
- lock_sock(sk);
-
- switch (optname) {
- case HCI_DATA_DIR:
-- if (get_user(opt, (int *)optval))
-- return -EFAULT;
-+ if (get_user(opt, (int *)optval)) {
-+ err = -EFAULT;
-+ break;
-+ }
-
- if (opt)
- hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
-@@ -372,12 +456,31 @@
- hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
- break;
-
-+ case HCI_TIME_STAMP:
-+ if (get_user(opt, (int *)optval)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (opt)
-+ hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
-+ else
-+ hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
-+ break;
-+
- case HCI_FILTER:
- len = MIN(len, sizeof(struct hci_filter));
- if (copy_from_user(&flt, optval, len)) {
- err = -EFAULT;
- break;
- }
-+
-+ if (!capable(CAP_NET_RAW)) {
-+ flt.type_mask &= hci_sec_filter.type_mask;
-+ flt.event_mask[0] &= hci_sec_filter.event_mask[0];
-+ flt.event_mask[1] &= hci_sec_filter.event_mask[1];
-+ }
-+
- memcpy(&hci_pi(sk)->filter, &flt, len);
- break;
-
-@@ -409,6 +512,16 @@
- return -EFAULT;
- break;
-
-+ case HCI_TIME_STAMP:
-+ if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
-+ opt = 1;
-+ else
-+ opt = 0;
-+
-+ if (put_user(opt, optval))
-+ return -EFAULT;
-+ break;
-+
- case HCI_FILTER:
- len = MIN(len, sizeof(struct hci_filter));
- if (copy_to_user(optval, &hci_pi(sk)->filter, len))
-@@ -446,7 +559,7 @@
- {
- struct sock *sk;
-
-- DBG("sock %p", sock);
-+ BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-@@ -464,44 +577,31 @@
- sk->protocol = protocol;
- sk->state = BT_OPEN;
-
-- /* Initialize filter */
-- hci_pi(sk)->filter.type_mask = (1<<HCI_EVENT_PKT);
-- hci_pi(sk)->filter.event_mask[0] = ~0L;
-- hci_pi(sk)->filter.event_mask[1] = ~0L;
--
- bluez_sock_link(&hci_sk_list, sk);
-
- MOD_INC_USE_COUNT;
--
- return 0;
- }
-
- static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
- {
- struct hci_dev *hdev = (struct hci_dev *) ptr;
-- struct sk_buff *skb;
--
-- DBG("hdev %s event %ld", hdev->name, event);
-+ evt_si_device sd;
-+
-+ BT_DBG("hdev %s event %ld", hdev->name, event);
-
- /* Send event to sockets */
-- if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
-- hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
-- evt_hci_dev_event he = { event, hdev->id };
--
-- skb->pkt_type = HCI_EVENT_PKT;
-- memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
-- memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
--
-- hci_send_to_sock(NULL, skb);
-- kfree_skb(skb);
-- }
--
-+ sd.event = event;
-+ sd.dev_id = hdev->id;
-+ hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd);
-+
- if (event == HCI_DEV_UNREG) {
- struct sock *sk;
-
- /* Detach sockets from device */
- read_lock(&hci_sk_list.lock);
- for (sk = hci_sk_list.head; sk; sk = sk->next) {
-+ bh_lock_sock(sk);
- if (hci_pi(sk)->hdev == hdev) {
- hci_pi(sk)->hdev = NULL;
- sk->err = EPIPE;
-@@ -510,6 +610,7 @@
-
- hci_dev_put(hdev);
- }
-+ bh_unlock_sock(sk);
- }
- read_unlock(&hci_sk_list.lock);
- }
-@@ -529,21 +630,19 @@
- int hci_sock_init(void)
- {
- if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
-- ERR("Can't register HCI socket");
-+ BT_ERR("Can't register HCI socket");
- return -EPROTO;
- }
-
- hci_register_notifier(&hci_sock_nblock);
--
- return 0;
- }
-
- int hci_sock_cleanup(void)
- {
- if (bluez_sock_unregister(BTPROTO_HCI))
-- ERR("Can't unregister HCI socket");
-+ BT_ERR("Can't unregister HCI socket");
-
- hci_unregister_notifier(&hci_sock_nblock);
--
- return 0;
- }
-diff -urN linux-2.4.18/net/bluetooth/hidp/Config.in linux-2.4.18-mh15/net/bluetooth/hidp/Config.in
---- linux-2.4.18/net/bluetooth/hidp/Config.in 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hidp/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,5 @@
-+#
-+# Bluetooth HIDP layer configuration
-+#
-+
-+dep_tristate 'HIDP protocol support' CONFIG_BLUEZ_HIDP $CONFIG_INPUT $CONFIG_BLUEZ_L2CAP
-diff -urN linux-2.4.18/net/bluetooth/hidp/core.c linux-2.4.18-mh15/net/bluetooth/hidp/core.c
---- linux-2.4.18/net/bluetooth/hidp/core.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hidp/core.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,655 @@
-+/*
-+ HIDP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <linux/init.h>
-+#include <net/sock.h>
-+
-+#include <linux/input.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "hidp.h"
-+
-+#ifndef CONFIG_BT_HIDP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.0"
-+
-+static DECLARE_RWSEM(hidp_session_sem);
-+static LIST_HEAD(hidp_session_list);
-+
-+static unsigned char hidp_keycode[256] = {
-+ 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
-+ 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
-+ 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
-+ 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
-+ 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
-+ 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
-+ 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
-+ 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
-+ 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
-+ 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
-+ 150,158,159,128,136,177,178,176,142,152,173,140
-+};
-+
-+static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
-+{
-+ struct hidp_session *session;
-+ struct list_head *p;
-+
-+ BT_DBG("");
-+
-+ list_for_each(p, &hidp_session_list) {
-+ session = list_entry(p, struct hidp_session, list);
-+ if (!bacmp(bdaddr, &session->bdaddr))
-+ return session;
-+ }
-+ return NULL;
-+}
-+
-+static void __hidp_link_session(struct hidp_session *session)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&session->list, &hidp_session_list);
-+}
-+
-+static void __hidp_unlink_session(struct hidp_session *session)
-+{
-+ list_del(&session->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
-+{
-+ bacpy(&ci->bdaddr, &session->bdaddr);
-+
-+ ci->flags = session->flags;
-+ ci->state = session->state;
-+
-+ ci->vendor = 0x0000;
-+ ci->product = 0x0000;
-+ ci->version = 0x0000;
-+ memset(ci->name, 0, 128);
-+
-+ if (session->input) {
-+ ci->vendor = session->input->idvendor;
-+ ci->product = session->input->idproduct;
-+ ci->version = session->input->idversion;
-+ if (session->input->name)
-+ strncpy(ci->name, session->input->name, 128);
-+ else
-+ strncpy(ci->name, "HID Boot Device", 128);
-+ }
-+}
-+
-+static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-+{
-+ struct hidp_session *session = dev->private;
-+ struct sk_buff *skb;
-+ unsigned char newleds;
-+
-+ BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
-+
-+ if (type != EV_LED)
-+ return -1;
-+
-+ newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
-+ (!!test_bit(LED_COMPOSE, dev->led) << 3) |
-+ (!!test_bit(LED_SCROLLL, dev->led) << 2) |
-+ (!!test_bit(LED_CAPSL, dev->led) << 1) |
-+ (!!test_bit(LED_NUML, dev->led));
-+
-+ if (session->leds == newleds)
-+ return 0;
-+
-+ session->leds = newleds;
-+
-+ if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new frame");
-+ return -ENOMEM;
-+ }
-+
-+ *skb_put(skb, 1) = 0xa2;
-+ *skb_put(skb, 1) = 0x01;
-+ *skb_put(skb, 1) = newleds;
-+
-+ skb_queue_tail(&session->intr_transmit, skb);
-+
-+ hidp_schedule(session);
-+
-+ return 0;
-+}
-+
-+static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
-+{
-+ struct input_dev *dev = session->input;
-+ unsigned char *keys = session->keys;
-+ unsigned char *udata = skb->data + 1;
-+ signed char *sdata = skb->data + 1;
-+ int i, size = skb->len - 1;
-+
-+ switch (skb->data[0]) {
-+ case 0x01: /* Keyboard report */
-+ for (i = 0; i < 8; i++)
-+ input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
-+
-+ for (i = 2; i < 8; i++) {
-+ if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
-+ if (hidp_keycode[keys[i]])
-+ input_report_key(dev, hidp_keycode[keys[i]], 0);
-+ else
-+ BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
-+ }
-+
-+ if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
-+ if (hidp_keycode[udata[i]])
-+ input_report_key(dev, hidp_keycode[udata[i]], 1);
-+ else
-+ BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
-+ }
-+ }
-+
-+ memcpy(keys, udata, 8);
-+ break;
-+
-+ case 0x02: /* Mouse report */
-+ input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
-+ input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
-+ input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
-+ input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
-+ input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
-+
-+ input_report_rel(dev, REL_X, sdata[1]);
-+ input_report_rel(dev, REL_Y, sdata[2]);
-+
-+ if (size > 3)
-+ input_report_rel(dev, REL_WHEEL, sdata[3]);
-+ break;
-+ }
-+
-+ input_event(dev, EV_RST, 0, 0);
-+}
-+
-+static void hidp_idle_timeout(unsigned long arg)
-+{
-+ struct hidp_session *session = (struct hidp_session *) arg;
-+
-+ atomic_inc(&session->terminate);
-+ hidp_schedule(session);
-+}
-+
-+static inline void hidp_set_timer(struct hidp_session *session)
-+{
-+ if (session->idle_to > 0)
-+ mod_timer(&session->timer, jiffies + HZ * session->idle_to);
-+}
-+
-+static inline void hidp_del_timer(struct hidp_session *session)
-+{
-+ if (session->idle_to > 0)
-+ del_timer(&session->timer);
-+}
-+
-+static inline void hidp_send_message(struct hidp_session *session, unsigned char hdr)
-+{
-+ struct sk_buff *skb;
-+
-+ BT_DBG("session %p", session);
-+
-+ if (!(skb = alloc_skb(1, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for message");
-+ return;
-+ }
-+
-+ *skb_put(skb, 1) = hdr;
-+
-+ skb_queue_tail(&session->ctrl_transmit, skb);
-+
-+ hidp_schedule(session);
-+}
-+
-+static inline int hidp_recv_frame(struct hidp_session *session, struct sk_buff *skb)
-+{
-+ __u8 hdr;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ hdr = skb->data[0];
-+ skb_pull(skb, 1);
-+
-+ if (hdr == 0xa1) {
-+ hidp_set_timer(session);
-+
-+ if (session->input)
-+ hidp_input_report(session, skb);
-+ } else {
-+ BT_DBG("Unsupported protocol header 0x%02x", hdr);
-+ }
-+
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
-+{
-+ struct iovec iv = { data, len };
-+ struct msghdr msg;
-+
-+ BT_DBG("sock %p data %p len %d", sock, data, len);
-+
-+ if (!len)
-+ return 0;
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ return sock_sendmsg(sock, &msg, len);
-+}
-+
-+static int hidp_process_transmit(struct hidp_session *session)
-+{
-+ struct sk_buff *skb;
-+
-+ BT_DBG("session %p", session);
-+
-+ while ((skb = skb_dequeue(&session->ctrl_transmit))) {
-+ if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
-+ skb_queue_head(&session->ctrl_transmit, skb);
-+ break;
-+ }
-+
-+ hidp_set_timer(session);
-+ kfree_skb(skb);
-+ }
-+
-+ while ((skb = skb_dequeue(&session->intr_transmit))) {
-+ if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
-+ skb_queue_head(&session->intr_transmit, skb);
-+ break;
-+ }
-+
-+ hidp_set_timer(session);
-+ kfree_skb(skb);
-+ }
-+
-+ return skb_queue_len(&session->ctrl_transmit) +
-+ skb_queue_len(&session->intr_transmit);
-+}
-+
-+static int hidp_session(void *arg)
-+{
-+ struct hidp_session *session = arg;
-+ struct sock *ctrl_sk = session->ctrl_sock->sk;
-+ struct sock *intr_sk = session->intr_sock->sk;
-+ struct sk_buff *skb;
-+ int vendor = 0x0000, product = 0x0000;
-+ wait_queue_t ctrl_wait, intr_wait;
-+ unsigned long timeo = HZ;
-+
-+ BT_DBG("session %p", session);
-+
-+ if (session->input) {
-+ vendor = session->input->idvendor;
-+ product = session->input->idproduct;
-+ }
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "khidpd_%04x%04x", vendor, product);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&ctrl_wait, current);
-+ init_waitqueue_entry(&intr_wait, current);
-+ add_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+ add_wait_queue(intr_sk->sleep, &intr_wait);
-+ while (!atomic_read(&session->terminate)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (ctrl_sk->state != BT_CONNECTED || intr_sk->state != BT_CONNECTED)
-+ break;
-+
-+ while ((skb = skb_dequeue(&ctrl_sk->receive_queue))) {
-+ skb_orphan(skb);
-+ hidp_recv_frame(session, skb);
-+ }
-+
-+ while ((skb = skb_dequeue(&intr_sk->receive_queue))) {
-+ skb_orphan(skb);
-+ hidp_recv_frame(session, skb);
-+ }
-+
-+ hidp_process_transmit(session);
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(intr_sk->sleep, &intr_wait);
-+ remove_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+
-+ down_write(&hidp_session_sem);
-+
-+ hidp_del_timer(session);
-+
-+ if (intr_sk->state != BT_CONNECTED) {
-+ init_waitqueue_entry(&ctrl_wait, current);
-+ add_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+ while (timeo && ctrl_sk->state != BT_CLOSED) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(ctrl_sk->sleep, &ctrl_wait);
-+ timeo = HZ;
-+ }
-+
-+ fput(session->ctrl_sock->file);
-+
-+ init_waitqueue_entry(&intr_wait, current);
-+ add_wait_queue(intr_sk->sleep, &intr_wait);
-+ while (timeo && intr_sk->state != BT_CLOSED) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(intr_sk->sleep, &intr_wait);
-+
-+ fput(session->intr_sock->file);
-+
-+ __hidp_unlink_session(session);
-+
-+ if (session->input) {
-+ input_unregister_device(session->input);
-+ kfree(session->input);
-+ }
-+
-+ up_write(&hidp_session_sem);
-+
-+ kfree(session);
-+ return 0;
-+}
-+
-+static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
-+{
-+ struct input_dev *input = session->input;
-+ int i;
-+
-+ input->private = session;
-+
-+ input->idbus = BUS_BLUETOOTH;
-+ input->idvendor = req->vendor;
-+ input->idproduct = req->product;
-+ input->idversion = req->version;
-+
-+ if (req->subclass & 0x40) {
-+ set_bit(EV_KEY, input->evbit);
-+ set_bit(EV_LED, input->evbit);
-+ set_bit(EV_REP, input->evbit);
-+
-+ set_bit(LED_NUML, input->ledbit);
-+ set_bit(LED_CAPSL, input->ledbit);
-+ set_bit(LED_SCROLLL, input->ledbit);
-+ set_bit(LED_COMPOSE, input->ledbit);
-+ set_bit(LED_KANA, input->ledbit);
-+
-+ for (i = 0; i < sizeof(hidp_keycode); i++)
-+ set_bit(hidp_keycode[i], input->keybit);
-+ clear_bit(0, input->keybit);
-+ }
-+
-+ if (req->subclass & 0x80) {
-+ input->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-+ input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-+ input->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-+ input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-+ input->relbit[0] |= BIT(REL_WHEEL);
-+ }
-+
-+ input->event = hidp_input_event;
-+
-+ input_register_device(input);
-+}
-+
-+int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
-+{
-+ struct hidp_session *session, *s;
-+ int err;
-+
-+ BT_DBG("");
-+
-+ if (bacmp(&bluez_pi(ctrl_sock->sk)->src, &bluez_pi(intr_sock->sk)->src) ||
-+ bacmp(&bluez_pi(ctrl_sock->sk)->dst, &bluez_pi(intr_sock->sk)->dst))
-+ return -ENOTUNIQ;
-+
-+ session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL);
-+ if (!session)
-+ return -ENOMEM;
-+ memset(session, 0, sizeof(struct hidp_session));
-+
-+ session->input = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
-+ if (!session->input) {
-+ kfree(session);
-+ return -ENOMEM;
-+ }
-+ memset(session->input, 0, sizeof(struct input_dev));
-+
-+ down_write(&hidp_session_sem);
-+
-+ s = __hidp_get_session(&bluez_pi(ctrl_sock->sk)->dst);
-+ if (s && s->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ bacpy(&session->bdaddr, &bluez_pi(ctrl_sock->sk)->dst);
-+
-+ session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
-+ session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
-+
-+ BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
-+
-+ session->ctrl_sock = ctrl_sock;
-+ session->intr_sock = intr_sock;
-+ session->state = BT_CONNECTED;
-+
-+ init_timer(&session->timer);
-+
-+ session->timer.function = hidp_idle_timeout;
-+ session->timer.data = (unsigned long) session;
-+
-+ skb_queue_head_init(&session->ctrl_transmit);
-+ skb_queue_head_init(&session->intr_transmit);
-+
-+ session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
-+ session->idle_to = req->idle_to;
-+
-+ if (session->input)
-+ hidp_setup_input(session, req);
-+
-+ __hidp_link_session(session);
-+
-+ hidp_set_timer(session);
-+
-+ err = kernel_thread(hidp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (err < 0)
-+ goto unlink;
-+
-+ if (session->input) {
-+ hidp_send_message(session, 0x70);
-+ session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
-+
-+ session->leds = 0xff;
-+ hidp_input_event(session->input, EV_LED, 0, 0);
-+ }
-+
-+ up_write(&hidp_session_sem);
-+ return 0;
-+
-+unlink:
-+ hidp_del_timer(session);
-+
-+ __hidp_unlink_session(session);
-+
-+ if (session->input)
-+ input_unregister_device(session->input);
-+
-+failed:
-+ up_write(&hidp_session_sem);
-+
-+ if (session->input)
-+ kfree(session->input);
-+
-+ kfree(session);
-+ return err;
-+}
-+
-+int hidp_del_connection(struct hidp_conndel_req *req)
-+{
-+ struct hidp_session *session;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&hidp_session_sem);
-+
-+ session = __hidp_get_session(&req->bdaddr);
-+ if (session) {
-+ if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
-+ hidp_send_message(session, 0x15);
-+ } else {
-+ /* Flush the transmit queues */
-+ skb_queue_purge(&session->ctrl_transmit);
-+ skb_queue_purge(&session->intr_transmit);
-+
-+ /* Kill session thread */
-+ atomic_inc(&session->terminate);
-+ hidp_schedule(session);
-+ }
-+ } else
-+ err = -ENOENT;
-+
-+ up_read(&hidp_session_sem);
-+ return err;
-+}
-+
-+int hidp_get_connlist(struct hidp_connlist_req *req)
-+{
-+ struct list_head *p;
-+ int err = 0, n = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&hidp_session_sem);
-+
-+ list_for_each(p, &hidp_session_list) {
-+ struct hidp_session *session;
-+ struct hidp_conninfo ci;
-+
-+ session = list_entry(p, struct hidp_session, list);
-+
-+ __hidp_copy_session(session, &ci);
-+
-+ if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (++n >= req->cnum)
-+ break;
-+
-+ req->ci++;
-+ }
-+ req->cnum = n;
-+
-+ up_read(&hidp_session_sem);
-+ return err;
-+}
-+
-+int hidp_get_conninfo(struct hidp_conninfo *ci)
-+{
-+ struct hidp_session *session;
-+ int err = 0;
-+
-+ down_read(&hidp_session_sem);
-+
-+ session = __hidp_get_session(&ci->bdaddr);
-+ if (session)
-+ __hidp_copy_session(session, ci);
-+ else
-+ err = -ENOENT;
-+
-+ up_read(&hidp_session_sem);
-+ return err;
-+}
-+
-+static int __init hidp_init(void)
-+{
-+ l2cap_load();
-+
-+ hidp_init_sockets();
-+
-+ BT_INFO("BlueZ HIDP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ return 0;
-+}
-+
-+static void __exit hidp_exit(void)
-+{
-+ hidp_cleanup_sockets();
-+}
-+
-+module_init(hidp_init);
-+module_exit(hidp_exit);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/hidp/hidp.h linux-2.4.18-mh15/net/bluetooth/hidp/hidp.h
---- linux-2.4.18/net/bluetooth/hidp/hidp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hidp/hidp.h 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,122 @@
-+/*
-+ HIDP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#ifndef __HIDP_H
-+#define __HIDP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+/* HIDP ioctl defines */
-+#define HIDPCONNADD _IOW('H', 200, int)
-+#define HIDPCONNDEL _IOW('H', 201, int)
-+#define HIDPGETCONNLIST _IOR('H', 210, int)
-+#define HIDPGETCONNINFO _IOR('H', 211, int)
-+
-+#define HIDP_VIRTUAL_CABLE_UNPLUG 0
-+#define HIDP_BOOT_PROTOCOL_MODE 1
-+#define HIDP_BLUETOOTH_VENDOR_ID 9
-+
-+struct hidp_connadd_req {
-+ int ctrl_sock; // Connected control socket
-+ int intr_sock; // Connteted interrupt socket
-+ __u16 parser;
-+ __u16 rd_size;
-+ __u8 *rd_data;
-+ __u8 country;
-+ __u8 subclass;
-+ __u16 vendor;
-+ __u16 product;
-+ __u16 version;
-+ __u32 flags;
-+ __u32 idle_to;
-+ char name[128];
-+};
-+
-+struct hidp_conndel_req {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+};
-+
-+struct hidp_conninfo {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+ __u16 state;
-+ __u16 vendor;
-+ __u16 product;
-+ __u16 version;
-+ char name[128];
-+};
-+
-+struct hidp_connlist_req {
-+ __u32 cnum;
-+ struct hidp_conninfo *ci;
-+};
-+
-+int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
-+int hidp_del_connection(struct hidp_conndel_req *req);
-+int hidp_get_connlist(struct hidp_connlist_req *req);
-+int hidp_get_conninfo(struct hidp_conninfo *ci);
-+
-+/* HIDP session defines */
-+struct hidp_session {
-+ struct list_head list;
-+
-+ struct socket *ctrl_sock;
-+ struct socket *intr_sock;
-+
-+ bdaddr_t bdaddr;
-+
-+ unsigned long state;
-+ unsigned long flags;
-+ unsigned long idle_to;
-+
-+ uint ctrl_mtu;
-+ uint intr_mtu;
-+
-+ atomic_t terminate;
-+
-+ unsigned char keys[8];
-+ unsigned char leds;
-+
-+ struct input_dev *input;
-+
-+ struct timer_list timer;
-+
-+ struct sk_buff_head ctrl_transmit;
-+ struct sk_buff_head intr_transmit;
-+};
-+
-+static inline void hidp_schedule(struct hidp_session *session)
-+{
-+ struct sock *ctrl_sk = session->ctrl_sock->sk;
-+ struct sock *intr_sk = session->intr_sock->sk;
-+
-+ wake_up_interruptible(ctrl_sk->sleep);
-+ wake_up_interruptible(intr_sk->sleep);
-+}
-+
-+/* HIDP init defines */
-+extern int __init hidp_init_sockets(void);
-+extern void __exit hidp_cleanup_sockets(void);
-+
-+#endif /* __HIDP_H */
-diff -urN linux-2.4.18/net/bluetooth/hidp/Makefile linux-2.4.18-mh15/net/bluetooth/hidp/Makefile
---- linux-2.4.18/net/bluetooth/hidp/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hidp/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth HIDP layer
-+#
-+
-+O_TARGET := hidp.o
-+
-+obj-y := core.o sock.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/hidp/sock.c linux-2.4.18-mh15/net/bluetooth/hidp/sock.c
---- linux-2.4.18/net/bluetooth/hidp/sock.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/hidp/sock.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,212 @@
-+/*
-+ HIDP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <linux/init.h>
-+#include <net/sock.h>
-+
-+#include "hidp.h"
-+
-+#ifndef CONFIG_BT_HIDP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static int hidp_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct hidp_connadd_req ca;
-+ struct hidp_conndel_req cd;
-+ struct hidp_connlist_req cl;
-+ struct hidp_conninfo ci;
-+ struct socket *csock;
-+ struct socket *isock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case HIDPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ csock = sockfd_lookup(ca.ctrl_sock, &err);
-+ if (!csock)
-+ return err;
-+
-+ isock = sockfd_lookup(ca.intr_sock, &err);
-+ if (!isock) {
-+ fput(csock->file);
-+ return err;
-+ }
-+
-+ if (csock->sk->state != BT_CONNECTED || isock->sk->state != BT_CONNECTED) {
-+ fput(csock->file);
-+ fput(isock->file);
-+ return -EBADFD;
-+ }
-+
-+ err = hidp_add_connection(&ca, csock, isock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else {
-+ fput(csock->file);
-+ fput(isock->file);
-+ }
-+
-+ return err;
-+
-+ case HIDPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return hidp_del_connection(&cd);
-+
-+ case HIDPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = hidp_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case HIDPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = hidp_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static struct proto_ops hidp_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: hidp_sock_release,
-+ ioctl: hidp_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int hidp_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &hidp_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family hidp_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: hidp_sock_create
-+};
-+
-+int __init hidp_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops)))
-+ BT_ERR("Can't register HIDP socket layer (%d)", err);
-+
-+ return err;
-+}
-+
-+void __exit hidp_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_unregister(BTPROTO_HIDP)))
-+ BT_ERR("Can't unregister HIDP socket layer (%d)", err);
-+}
-diff -urN linux-2.4.18/net/bluetooth/l2cap.c linux-2.4.18-mh15/net/bluetooth/l2cap.c
---- linux-2.4.18/net/bluetooth/l2cap.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/l2cap.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,2222 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ L2CAP core and sockets.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "2.3"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#ifndef L2CAP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static struct proto_ops l2cap_sock_ops;
-+
-+struct bluez_sock_list l2cap_sk_list = {
-+ lock: RW_LOCK_UNLOCKED
-+};
-+
-+static int l2cap_conn_del(struct hci_conn *conn, int err);
-+
-+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
-+static void l2cap_chan_del(struct sock *sk, int err);
-+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
-+
-+static void __l2cap_sock_close(struct sock *sk, int reason);
-+static void l2cap_sock_close(struct sock *sk);
-+static void l2cap_sock_kill(struct sock *sk);
-+
-+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
-+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
-+
-+/* ----- L2CAP timers ------ */
-+static void l2cap_sock_timeout(unsigned long arg)
-+{
-+ struct sock *sk = (struct sock *) arg;
-+
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ bh_lock_sock(sk);
-+ __l2cap_sock_close(sk, ETIMEDOUT);
-+ bh_unlock_sock(sk);
-+
-+ l2cap_sock_kill(sk);
-+ sock_put(sk);
-+}
-+
-+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
-+{
-+ BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout);
-+
-+ if (!mod_timer(&sk->timer, jiffies + timeout))
-+ sock_hold(sk);
-+}
-+
-+static void l2cap_sock_clear_timer(struct sock *sk)
-+{
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-+ __sock_put(sk);
-+}
-+
-+static void l2cap_sock_init_timer(struct sock *sk)
-+{
-+ init_timer(&sk->timer);
-+ sk->timer.function = l2cap_sock_timeout;
-+ sk->timer.data = (unsigned long)sk;
-+}
-+
-+/* -------- L2CAP connections --------- */
-+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status)
-+{
-+ struct l2cap_conn *conn;
-+
-+ if ((conn = hcon->l2cap_data))
-+ return conn;
-+
-+ if (status)
-+ return conn;
-+
-+ if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
-+ return NULL;
-+ memset(conn, 0, sizeof(struct l2cap_conn));
-+
-+ hcon->l2cap_data = conn;
-+ conn->hcon = hcon;
-+
-+ conn->mtu = hcon->hdev->acl_mtu;
-+ conn->src = &hcon->hdev->bdaddr;
-+ conn->dst = &hcon->dst;
-+
-+ spin_lock_init(&conn->lock);
-+ conn->chan_list.lock = RW_LOCK_UNLOCKED;
-+
-+ BT_DBG("hcon %p conn %p", hcon, conn);
-+
-+ MOD_INC_USE_COUNT;
-+ return conn;
-+}
-+
-+static int l2cap_conn_del(struct hci_conn *hcon, int err)
-+{
-+ struct l2cap_conn *conn;
-+ struct sock *sk;
-+
-+ if (!(conn = hcon->l2cap_data))
-+ return 0;
-+
-+ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-+
-+ if (conn->rx_skb)
-+ kfree_skb(conn->rx_skb);
-+
-+ /* Kill channels */
-+ while ((sk = conn->chan_list.head)) {
-+ bh_lock_sock(sk);
-+ l2cap_chan_del(sk, err);
-+ bh_unlock_sock(sk);
-+ l2cap_sock_kill(sk);
-+ }
-+
-+ hcon->l2cap_data = NULL;
-+ kfree(conn);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+/* -------- Socket interface ---------- */
-+static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
-+{
-+ struct sock *sk;
-+ for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+ if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+ }
-+ return sk;
-+}
-+
-+/* Find socket with psm and source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
-+{
-+ struct sock *sk, *sk1 = NULL;
-+
-+ for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+ if (state && sk->state != state)
-+ continue;
-+
-+ if (l2cap_pi(sk)->psm == psm) {
-+ /* Exact match. */
-+ if (!bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+
-+ /* Closest match */
-+ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ sk1 = sk;
-+ }
-+ }
-+ return sk ? sk : sk1;
-+}
-+
-+/* Find socket with given address (psm, src).
-+ * Returns locked socket */
-+static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
-+{
-+ struct sock *s;
-+ read_lock(&l2cap_sk_list.lock);
-+ s = __l2cap_get_sock_by_psm(state, psm, src);
-+ if (s) bh_lock_sock(s);
-+ read_unlock(&l2cap_sk_list.lock);
-+ return s;
-+}
-+
-+static void l2cap_sock_destruct(struct sock *sk)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ skb_queue_purge(&sk->receive_queue);
-+ skb_queue_purge(&sk->write_queue);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void l2cap_sock_cleanup_listen(struct sock *parent)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ /* Close not yet accepted channels */
-+ while ((sk = bluez_accept_dequeue(parent, NULL)))
-+ l2cap_sock_close(sk);
-+
-+ parent->state = BT_CLOSED;
-+ parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void l2cap_sock_kill(struct sock *sk)
-+{
-+ if (!sk->zapped || sk->socket)
-+ return;
-+
-+ BT_DBG("sk %p state %d", sk, sk->state);
-+
-+ /* Kill poor orphan */
-+ bluez_sock_unlink(&l2cap_sk_list, sk);
-+ sk->dead = 1;
-+ sock_put(sk);
-+}
-+
-+/* Close socket.
-+ */
-+static void __l2cap_sock_close(struct sock *sk, int reason)
-+{
-+ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-+
-+ switch (sk->state) {
-+ case BT_LISTEN:
-+ l2cap_sock_cleanup_listen(sk);
-+ break;
-+
-+ case BT_CONNECTED:
-+ case BT_CONFIG:
-+ case BT_CONNECT2:
-+ if (sk->type == SOCK_SEQPACKET) {
-+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+ l2cap_disconn_req req;
-+
-+ sk->state = BT_DISCONN;
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+ } else {
-+ l2cap_chan_del(sk, reason);
-+ }
-+ break;
-+
-+ case BT_CONNECT:
-+ case BT_DISCONN:
-+ l2cap_chan_del(sk, reason);
-+ break;
-+
-+ default:
-+ sk->zapped = 1;
-+ break;
-+ };
-+}
-+
-+/* Must be called on unlocked socket. */
-+static void l2cap_sock_close(struct sock *sk)
-+{
-+ l2cap_sock_clear_timer(sk);
-+ lock_sock(sk);
-+ __l2cap_sock_close(sk, ECONNRESET);
-+ release_sock(sk);
-+ l2cap_sock_kill(sk);
-+}
-+
-+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
-+{
-+ struct l2cap_pinfo *pi = l2cap_pi(sk);
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (parent) {
-+ sk->type = parent->type;
-+ pi->imtu = l2cap_pi(parent)->imtu;
-+ pi->omtu = l2cap_pi(parent)->omtu;
-+ pi->link_mode = l2cap_pi(parent)->link_mode;
-+ } else {
-+ pi->imtu = L2CAP_DEFAULT_MTU;
-+ pi->omtu = 0;
-+ pi->link_mode = 0;
-+ }
-+
-+ /* Default config options */
-+ pi->conf_mtu = L2CAP_DEFAULT_MTU;
-+ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
-+}
-+
-+static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+ struct sock *sk;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-+ return NULL;
-+
-+ bluez_sock_init(sock, sk);
-+
-+ sk->zapped = 0;
-+
-+ sk->destruct = l2cap_sock_destruct;
-+ sk->sndtimeo = L2CAP_CONN_TIMEOUT;
-+
-+ sk->protocol = proto;
-+ sk->state = BT_OPEN;
-+
-+ l2cap_sock_init_timer(sk);
-+
-+ bluez_sock_link(&l2cap_sk_list, sk);
-+
-+ MOD_INC_USE_COUNT;
-+ return sk;
-+}
-+
-+static int l2cap_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ sock->state = SS_UNCONNECTED;
-+
-+ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
-+ return -EPERM;
-+
-+ sock->ops = &l2cap_sock_ops;
-+
-+ if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ l2cap_sock_init(sk, NULL);
-+ return 0;
-+}
-+
-+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
-+
-+ if (!addr || addr->sa_family != AF_BLUETOOTH)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_OPEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ write_lock_bh(&l2cap_sk_list.lock);
-+ if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
-+ err = -EADDRINUSE;
-+ } else {
-+ /* Save source address */
-+ bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
-+ l2cap_pi(sk)->psm = la->l2_psm;
-+ sk->sport = la->l2_psm;
-+ sk->state = BT_BOUND;
-+ }
-+ write_unlock_bh(&l2cap_sk_list.lock);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_do_connect(struct sock *sk)
-+{
-+ bdaddr_t *src = &bluez_pi(sk)->src;
-+ bdaddr_t *dst = &bluez_pi(sk)->dst;
-+ struct l2cap_conn *conn;
-+ struct hci_conn *hcon;
-+ struct hci_dev *hdev;
-+ int err = 0;
-+
-+ BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
-+
-+ if (!(hdev = hci_get_route(dst, src)))
-+ return -EHOSTUNREACH;
-+
-+ hci_dev_lock_bh(hdev);
-+
-+ err = -ENOMEM;
-+
-+ hcon = hci_connect(hdev, ACL_LINK, dst);
-+ if (!hcon)
-+ goto done;
-+
-+ conn = l2cap_conn_add(hcon, 0);
-+ if (!conn) {
-+ hci_conn_put(hcon);
-+ goto done;
-+ }
-+
-+ err = 0;
-+
-+ /* Update source addr of the socket */
-+ bacpy(src, conn->src);
-+
-+ l2cap_chan_add(conn, sk, NULL);
-+
-+ sk->state = BT_CONNECT;
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+ if (hcon->state == BT_CONNECTED) {
-+ if (sk->type == SOCK_SEQPACKET) {
-+ l2cap_conn_req req;
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ req.psm = l2cap_pi(sk)->psm;
-+ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-+ } else {
-+ l2cap_sock_clear_timer(sk);
-+ sk->state = BT_CONNECTED;
-+ }
-+ }
-+
-+done:
-+ hci_dev_unlock_bh(hdev);
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
-+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-+ err = -EINVAL;
-+ goto done;
-+ }
-+
-+ if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
-+ err = -EINVAL;
-+ goto done;
-+ }
-+
-+ switch(sk->state) {
-+ case BT_CONNECT:
-+ case BT_CONNECT2:
-+ case BT_CONFIG:
-+ /* Already connecting */
-+ goto wait;
-+
-+ case BT_CONNECTED:
-+ /* Already connected */
-+ goto done;
-+
-+ case BT_OPEN:
-+ case BT_BOUND:
-+ /* Can connect */
-+ break;
-+
-+ default:
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ /* Set destination address and psm */
-+ bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
-+ l2cap_pi(sk)->psm = la->l2_psm;
-+
-+ if ((err = l2cap_do_connect(sk)))
-+ goto done;
-+
-+wait:
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int l2cap_sock_listen(struct socket *sock, int backlog)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ if (!l2cap_pi(sk)->psm) {
-+ err = -EINVAL;
-+ goto done;
-+ }
-+
-+ sk->max_ack_backlog = backlog;
-+ sk->ack_backlog = 0;
-+ sk->state = BT_LISTEN;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct sock *sk = sock->sk, *nsk;
-+ long timeo;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+ BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+ /* Wait for an incoming connection. (wake-one). */
-+ add_wait_queue_exclusive(sk->sleep, &wait);
-+ while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ if (err)
-+ goto done;
-+
-+ newsock->state = SS_CONNECTED;
-+
-+ BT_DBG("new socket %p", nsk);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ addr->sa_family = AF_BLUETOOTH;
-+ *len = sizeof(struct sockaddr_l2);
-+
-+ if (peer)
-+ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
-+ else
-+ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
-+
-+ la->l2_psm = l2cap_pi(sk)->psm;
-+ return 0;
-+}
-+
-+static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (sk->err)
-+ return sock_error(sk);
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ /* Check outgoing MTU */
-+ if (len > l2cap_pi(sk)->omtu)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state == BT_CONNECTED)
-+ err = l2cap_chan_send(sk, msg, len);
-+ else
-+ err = -ENOTCONN;
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ struct l2cap_options opts;
-+ int err = 0, len;
-+ __u32 opt;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ case L2CAP_OPTIONS:
-+ len = MIN(sizeof(opts), optlen);
-+ if (copy_from_user((char *)&opts, optval, len)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+ l2cap_pi(sk)->imtu = opts.imtu;
-+ l2cap_pi(sk)->omtu = opts.omtu;
-+ break;
-+
-+ case L2CAP_LM:
-+ if (get_user(opt, (__u32 *)optval)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ l2cap_pi(sk)->link_mode = opt;
-+ break;
-+
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ struct l2cap_options opts;
-+ struct l2cap_conninfo cinfo;
-+ int len, err = 0;
-+
-+ if (get_user(len, optlen))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ case L2CAP_OPTIONS:
-+ opts.imtu = l2cap_pi(sk)->imtu;
-+ opts.omtu = l2cap_pi(sk)->omtu;
-+ opts.flush_to = l2cap_pi(sk)->flush_to;
-+
-+ len = MIN(len, sizeof(opts));
-+ if (copy_to_user(optval, (char *)&opts, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ case L2CAP_LM:
-+ if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))
-+ err = -EFAULT;
-+ break;
-+
-+ case L2CAP_CONNINFO:
-+ if (sk->state != BT_CONNECTED) {
-+ err = -ENOTCONN;
-+ break;
-+ }
-+
-+ cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
-+
-+ len = MIN(len, sizeof(cinfo));
-+ if (copy_to_user(optval, (char *)&cinfo, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_shutdown(struct socket *sock, int how)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ lock_sock(sk);
-+ if (!sk->shutdown) {
-+ sk->shutdown = SHUTDOWN_MASK;
-+ l2cap_sock_clear_timer(sk);
-+ __l2cap_sock_close(sk, 0);
-+
-+ if (sk->linger)
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ }
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+ int err;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ err = l2cap_sock_shutdown(sock, 2);
-+
-+ sock_orphan(sk);
-+ l2cap_sock_kill(sk);
-+ return err;
-+}
-+
-+/* --------- L2CAP channels --------- */
-+static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+ struct sock *s;
-+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-+ if (l2cap_pi(s)->dcid == cid)
-+ break;
-+ }
-+ return s;
-+}
-+
-+static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+ struct sock *s;
-+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-+ if (l2cap_pi(s)->scid == cid)
-+ break;
-+ }
-+ return s;
-+}
-+
-+/* Find channel with given SCID.
-+ * Returns locked socket */
-+static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+ struct sock *s;
-+ read_lock(&l->lock);
-+ s = __l2cap_get_chan_by_scid(l, cid);
-+ if (s) bh_lock_sock(s);
-+ read_unlock(&l->lock);
-+ return s;
-+}
-+
-+static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
-+{
-+ __u16 cid = 0x0040;
-+
-+ for (; cid < 0xffff; cid++) {
-+ if(!__l2cap_get_chan_by_scid(l, cid))
-+ return cid;
-+ }
-+
-+ return 0;
-+}
-+
-+static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
-+{
-+ sock_hold(sk);
-+
-+ if (l->head)
-+ l2cap_pi(l->head)->prev_c = sk;
-+
-+ l2cap_pi(sk)->next_c = l->head;
-+ l2cap_pi(sk)->prev_c = NULL;
-+ l->head = sk;
-+}
-+
-+static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
-+{
-+ struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
-+
-+ write_lock(&l->lock);
-+ if (sk == l->head)
-+ l->head = next;
-+
-+ if (next)
-+ l2cap_pi(next)->prev_c = prev;
-+ if (prev)
-+ l2cap_pi(prev)->next_c = next;
-+ write_unlock(&l->lock);
-+
-+ __sock_put(sk);
-+}
-+
-+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+
-+ BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
-+
-+ l2cap_pi(sk)->conn = conn;
-+
-+ if (sk->type == SOCK_SEQPACKET) {
-+ /* Alloc CID for connection-oriented socket */
-+ l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
-+ } else if (sk->type == SOCK_DGRAM) {
-+ /* Connectionless socket */
-+ l2cap_pi(sk)->scid = 0x0002;
-+ l2cap_pi(sk)->dcid = 0x0002;
-+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-+ } else {
-+ /* Raw socket can send/recv signalling messages only */
-+ l2cap_pi(sk)->scid = 0x0001;
-+ l2cap_pi(sk)->dcid = 0x0001;
-+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-+ }
-+
-+ __l2cap_chan_link(l, sk);
-+
-+ if (parent)
-+ bluez_accept_enqueue(parent, sk);
-+}
-+
-+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ write_lock(&l->lock);
-+ __l2cap_chan_add(conn, sk, parent);
-+ write_unlock(&l->lock);
-+}
-+
-+/* Delete channel.
-+ * Must be called on the locked socket. */
-+static void l2cap_chan_del(struct sock *sk, int err)
-+{
-+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+ struct sock *parent = bluez_pi(sk)->parent;
-+
-+ l2cap_sock_clear_timer(sk);
-+
-+ BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-+
-+ if (conn) {
-+ /* Unlink from channel list */
-+ l2cap_chan_unlink(&conn->chan_list, sk);
-+ l2cap_pi(sk)->conn = NULL;
-+ hci_conn_put(conn->hcon);
-+ }
-+
-+ sk->state = BT_CLOSED;
-+ sk->zapped = 1;
-+
-+ if (err)
-+ sk->err = err;
-+
-+ if (parent)
-+ parent->data_ready(parent, 0);
-+ else
-+ sk->state_change(sk);
-+}
-+
-+static void l2cap_conn_ready(struct l2cap_conn *conn)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sock *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ bh_lock_sock(sk);
-+
-+ if (sk->type != SOCK_SEQPACKET) {
-+ l2cap_sock_clear_timer(sk);
-+ sk->state = BT_CONNECTED;
-+ sk->state_change(sk);
-+ } else if (sk->state == BT_CONNECT) {
-+ l2cap_conn_req req;
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ req.psm = l2cap_pi(sk)->psm;
-+ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-+ }
-+
-+ bh_unlock_sock(sk);
-+ }
-+
-+ read_unlock(&l->lock);
-+}
-+
-+/* Notify sockets that we cannot guaranty reliability anymore */
-+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sock *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
-+ sk->err = err;
-+ }
-+ read_unlock(&l->lock);
-+}
-+
-+static void l2cap_chan_ready(struct sock *sk)
-+{
-+ struct sock *parent = bluez_pi(sk)->parent;
-+
-+ BT_DBG("sk %p, parent %p", sk, parent);
-+
-+ l2cap_pi(sk)->conf_state = 0;
-+ l2cap_sock_clear_timer(sk);
-+
-+ if (!parent) {
-+ /* Outgoing channel.
-+ * Wake up socket sleeping on connect.
-+ */
-+ sk->state = BT_CONNECTED;
-+ sk->state_change(sk);
-+ } else {
-+ /* Incomming channel.
-+ * Wake up socket sleeping on accept.
-+ */
-+ parent->data_ready(parent, 0);
-+ }
-+}
-+
-+/* Copy frame to all raw sockets on that connection */
-+void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sk_buff *nskb;
-+ struct sock * sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ if (sk->type != SOCK_RAW)
-+ continue;
-+
-+ /* Don't send frame to the socket it came from */
-+ if (skb->sk == sk)
-+ continue;
-+
-+ if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
-+ continue;
-+
-+ if (sock_queue_rcv_skb(sk, nskb))
-+ kfree_skb(nskb);
-+ }
-+ read_unlock(&l->lock);
-+}
-+
-+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
-+{
-+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+ struct sk_buff *skb, **frag;
-+ int err, hlen, count, sent=0;
-+ l2cap_hdr *lh;
-+
-+ BT_DBG("sk %p len %d", sk, len);
-+
-+ /* First fragment (with L2CAP header) */
-+ if (sk->type == SOCK_DGRAM)
-+ hlen = L2CAP_HDR_SIZE + 2;
-+ else
-+ hlen = L2CAP_HDR_SIZE;
-+
-+ count = MIN(conn->mtu - hlen, len);
-+
-+ skb = bluez_skb_send_alloc(sk, hlen + count,
-+ msg->msg_flags & MSG_DONTWAIT, &err);
-+ if (!skb)
-+ return err;
-+
-+ /* Create L2CAP header */
-+ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-+ lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-+
-+ if (sk->type == SOCK_DGRAM)
-+ put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
-+
-+ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-+ err = -EFAULT;
-+ goto fail;
-+ }
-+
-+ sent += count;
-+ len -= count;
-+
-+ /* Continuation fragments (no L2CAP header) */
-+ frag = &skb_shinfo(skb)->frag_list;
-+ while (len) {
-+ count = MIN(conn->mtu, len);
-+
-+ *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
-+ if (!*frag)
-+ goto fail;
-+
-+ if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
-+ err = -EFAULT;
-+ goto fail;
-+ }
-+
-+ sent += count;
-+ len -= count;
-+
-+ frag = &(*frag)->next;
-+ }
-+
-+ if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
-+ goto fail;
-+
-+ return sent;
-+
-+fail:
-+ kfree_skb(skb);
-+ return err;
-+}
-+
-+/* --------- L2CAP signalling commands --------- */
-+static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
-+{
-+ __u8 id;
-+
-+ /* Get next available identificator.
-+ * 1 - 199 are used by kernel.
-+ * 200 - 254 are used by utilities like l2ping, etc
-+ */
-+
-+ spin_lock(&conn->lock);
-+
-+ if (++conn->tx_ident > 199)
-+ conn->tx_ident = 1;
-+
-+ id = conn->tx_ident;
-+
-+ spin_unlock(&conn->lock);
-+
-+ return id;
-+}
-+
-+static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
-+ __u8 code, __u8 ident, __u16 dlen, void *data)
-+{
-+ struct sk_buff *skb, **frag;
-+ l2cap_cmd_hdr *cmd;
-+ l2cap_hdr *lh;
-+ int len, count;
-+
-+ BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
-+
-+ len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
-+ count = MIN(conn->mtu, len);
-+
-+ skb = bluez_skb_alloc(count, GFP_ATOMIC);
-+ if (!skb)
-+ return NULL;
-+
-+ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-+ lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-+ lh->cid = __cpu_to_le16(0x0001);
-+
-+ cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
-+ cmd->code = code;
-+ cmd->ident = ident;
-+ cmd->len = __cpu_to_le16(dlen);
-+
-+ if (dlen) {
-+ count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
-+ memcpy(skb_put(skb, count), data, count);
-+ data += count;
-+ }
-+
-+ len -= skb->len;
-+
-+ /* Continuation fragments (no L2CAP header) */
-+ frag = &skb_shinfo(skb)->frag_list;
-+ while (len) {
-+ count = MIN(conn->mtu, len);
-+
-+ *frag = bluez_skb_alloc(count, GFP_ATOMIC);
-+ if (!*frag)
-+ goto fail;
-+
-+ memcpy(skb_put(*frag, count), data, count);
-+
-+ len -= count;
-+ data += count;
-+
-+ frag = &(*frag)->next;
-+ }
-+
-+ return skb;
-+
-+fail:
-+ kfree_skb(skb);
-+ return NULL;
-+}
-+
-+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
-+{
-+ __u8 ident = l2cap_get_ident(conn);
-+ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-+
-+ BT_DBG("code 0x%2.2x", code);
-+
-+ if (!skb)
-+ return -ENOMEM;
-+ return hci_send_acl(conn->hcon, skb, 0);
-+}
-+
-+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
-+{
-+ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-+
-+ BT_DBG("code 0x%2.2x", code);
-+
-+ if (!skb)
-+ return -ENOMEM;
-+ return hci_send_acl(conn->hcon, skb, 0);
-+}
-+
-+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
-+{
-+ l2cap_conf_opt *opt = *ptr;
-+ int len;
-+
-+ len = L2CAP_CONF_OPT_SIZE + opt->len;
-+ *ptr += len;
-+
-+ *type = opt->type;
-+ *olen = opt->len;
-+
-+ switch (opt->len) {
-+ case 1:
-+ *val = *((__u8 *) opt->val);
-+ break;
-+
-+ case 2:
-+ *val = __le16_to_cpu(*((__u16 *)opt->val));
-+ break;
-+
-+ case 4:
-+ *val = __le32_to_cpu(*((__u32 *)opt->val));
-+ break;
-+
-+ default:
-+ *val = (unsigned long) opt->val;
-+ break;
-+ };
-+
-+ BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
-+ return len;
-+}
-+
-+static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len)
-+{
-+ int type, hint, olen;
-+ unsigned long val;
-+ void *ptr = data;
-+
-+ BT_DBG("sk %p len %d", sk, len);
-+
-+ while (len >= L2CAP_CONF_OPT_SIZE) {
-+ len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
-+
-+ hint = type & 0x80;
-+ type &= 0x7f;
-+
-+ switch (type) {
-+ case L2CAP_CONF_MTU:
-+ l2cap_pi(sk)->conf_mtu = val;
-+ break;
-+
-+ case L2CAP_CONF_FLUSH_TO:
-+ l2cap_pi(sk)->flush_to = val;
-+ break;
-+
-+ case L2CAP_CONF_QOS:
-+ break;
-+
-+ default:
-+ if (hint)
-+ break;
-+
-+ /* FIXME: Reject unknown option */
-+ break;
-+ };
-+ }
-+}
-+
-+static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val)
-+{
-+ register l2cap_conf_opt *opt = *ptr;
-+
-+ BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
-+
-+ opt->type = type;
-+ opt->len = len;
-+
-+ switch (len) {
-+ case 1:
-+ *((__u8 *) opt->val) = val;
-+ break;
-+
-+ case 2:
-+ *((__u16 *) opt->val) = __cpu_to_le16(val);
-+ break;
-+
-+ case 4:
-+ *((__u32 *) opt->val) = __cpu_to_le32(val);
-+ break;
-+
-+ default:
-+ memcpy(opt->val, (void *) val, len);
-+ break;
-+ };
-+
-+ *ptr += L2CAP_CONF_OPT_SIZE + len;
-+}
-+
-+static int l2cap_build_conf_req(struct sock *sk, void *data)
-+{
-+ struct l2cap_pinfo *pi = l2cap_pi(sk);
-+ l2cap_conf_req *req = (l2cap_conf_req *) data;
-+ void *ptr = req->data;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (pi->imtu != L2CAP_DEFAULT_MTU)
-+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
-+
-+ /* FIXME. Need actual value of the flush timeout */
-+ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-+ // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
-+
-+ req->dcid = __cpu_to_le16(pi->dcid);
-+ req->flags = __cpu_to_le16(0);
-+
-+ return ptr - data;
-+}
-+
-+static inline int l2cap_conf_output(struct sock *sk, void **ptr)
-+{
-+ struct l2cap_pinfo *pi = l2cap_pi(sk);
-+ int result = 0;
-+
-+ /* Configure output options and let the other side know
-+ * which ones we don't like.
-+ */
-+ if (pi->conf_mtu < pi->omtu) {
-+ l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
-+ result = L2CAP_CONF_UNACCEPT;
-+ } else {
-+ pi->omtu = pi->conf_mtu;
-+ }
-+
-+ BT_DBG("sk %p result %d", sk, result);
-+ return result;
-+}
-+
-+static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
-+{
-+ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
-+ void *ptr = rsp->data;
-+ u16 flags = 0;
-+
-+ BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
-+
-+ if (result)
-+ *result = l2cap_conf_output(sk, &ptr);
-+ else
-+ flags |= 0x0001;
-+
-+ rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ rsp->result = __cpu_to_le16(result ? *result : 0);
-+ rsp->flags = __cpu_to_le16(flags);
-+
-+ return ptr - data;
-+}
-+
-+static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ struct l2cap_chan_list *list = &conn->chan_list;
-+ l2cap_conn_req *req = (l2cap_conn_req *) data;
-+ l2cap_conn_rsp rsp;
-+ struct sock *sk, *parent;
-+ int result = 0, status = 0;
-+
-+ __u16 dcid = 0, scid = __le16_to_cpu(req->scid);
-+ __u16 psm = req->psm;
-+
-+ BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
-+
-+ /* Check if we have socket listening on psm */
-+ parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
-+ if (!parent) {
-+ result = L2CAP_CR_BAD_PSM;
-+ goto sendresp;
-+ }
-+
-+ result = L2CAP_CR_NO_MEM;
-+
-+ /* Check for backlog size */
-+ if (parent->ack_backlog > parent->max_ack_backlog) {
-+ BT_DBG("backlog full %d", parent->ack_backlog);
-+ goto response;
-+ }
-+
-+ sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
-+ if (!sk)
-+ goto response;
-+
-+ write_lock(&list->lock);
-+
-+ /* Check if we already have channel with that dcid */
-+ if (__l2cap_get_chan_by_dcid(list, scid)) {
-+ write_unlock(&list->lock);
-+ sk->zapped = 1;
-+ l2cap_sock_kill(sk);
-+ goto response;
-+ }
-+
-+ hci_conn_hold(conn->hcon);
-+
-+ l2cap_sock_init(sk, parent);
-+ bacpy(&bluez_pi(sk)->src, conn->src);
-+ bacpy(&bluez_pi(sk)->dst, conn->dst);
-+ l2cap_pi(sk)->psm = psm;
-+ l2cap_pi(sk)->dcid = scid;
-+
-+ __l2cap_chan_add(conn, sk, parent);
-+ dcid = l2cap_pi(sk)->scid;
-+
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+ /* Service level security */
-+ result = L2CAP_CR_PEND;
-+ status = L2CAP_CS_AUTHEN_PEND;
-+ sk->state = BT_CONNECT2;
-+ l2cap_pi(sk)->ident = cmd->ident;
-+
-+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
-+ if (!hci_conn_encrypt(conn->hcon))
-+ goto done;
-+ } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
-+ if (!hci_conn_auth(conn->hcon))
-+ goto done;
-+ }
-+
-+ sk->state = BT_CONFIG;
-+ result = status = 0;
-+
-+done:
-+ write_unlock(&list->lock);
-+
-+response:
-+ bh_unlock_sock(parent);
-+
-+sendresp:
-+ rsp.scid = __cpu_to_le16(scid);
-+ rsp.dcid = __cpu_to_le16(dcid);
-+ rsp.result = __cpu_to_le16(result);
-+ rsp.status = __cpu_to_le16(status);
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
-+ return 0;
-+}
-+
-+static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
-+ __u16 scid, dcid, result, status;
-+ struct sock *sk;
-+ char req[128];
-+
-+ scid = __le16_to_cpu(rsp->scid);
-+ dcid = __le16_to_cpu(rsp->dcid);
-+ result = __le16_to_cpu(rsp->result);
-+ status = __le16_to_cpu(rsp->status);
-+
-+ BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+ return -ENOENT;
-+
-+ switch (result) {
-+ case L2CAP_CR_SUCCESS:
-+ sk->state = BT_CONFIG;
-+ l2cap_pi(sk)->dcid = dcid;
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
-+
-+ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-+ break;
-+
-+ case L2CAP_CR_PEND:
-+ break;
-+
-+ default:
-+ l2cap_chan_del(sk, ECONNREFUSED);
-+ break;
-+ }
-+
-+ bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_conf_req * req = (l2cap_conf_req *) data;
-+ __u16 dcid, flags;
-+ __u8 rsp[64];
-+ struct sock *sk;
-+ int result;
-+
-+ dcid = __le16_to_cpu(req->dcid);
-+ flags = __le16_to_cpu(req->flags);
-+
-+ BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-+ return -ENOENT;
-+
-+ l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
-+
-+ if (flags & 0x0001) {
-+ /* Incomplete config. Send empty response. */
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
-+ goto unlock;
-+ }
-+
-+ /* Complete config. */
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
-+
-+ if (result)
-+ goto unlock;
-+
-+ /* Output config done */
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-+
-+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
-+ sk->state = BT_CONNECTED;
-+ l2cap_chan_ready(sk);
-+ } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
-+ char req[64];
-+ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-+ }
-+
-+unlock:
-+ bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
-+ __u16 scid, flags, result;
-+ struct sock *sk;
-+ int err = 0;
-+
-+ scid = __le16_to_cpu(rsp->scid);
-+ flags = __le16_to_cpu(rsp->flags);
-+ result = __le16_to_cpu(rsp->result);
-+
-+ BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+ return -ENOENT;
-+
-+ switch (result) {
-+ case L2CAP_CONF_SUCCESS:
-+ break;
-+
-+ case L2CAP_CONF_UNACCEPT:
-+ if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
-+ char req[128];
-+ /*
-+ It does not make sense to adjust L2CAP parameters
-+ that are currently defined in the spec. We simply
-+ resend config request that we sent earlier. It is
-+ stupid :) but it helps qualification testing
-+ which expects at least some response from us.
-+ */
-+ l2cap_send_req(conn, L2CAP_CONF_REQ,
-+ l2cap_build_conf_req(sk, req), req);
-+ goto done;
-+ }
-+ default:
-+ sk->state = BT_DISCONN;
-+ sk->err = ECONNRESET;
-+ l2cap_sock_set_timer(sk, HZ * 5);
-+ {
-+ l2cap_disconn_req req;
-+ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+ }
-+ goto done;
-+ }
-+
-+ if (flags & 0x01)
-+ goto done;
-+
-+ /* Input config done */
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
-+
-+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
-+ sk->state = BT_CONNECTED;
-+ l2cap_chan_ready(sk);
-+ }
-+
-+done:
-+ bh_unlock_sock(sk);
-+ return err;
-+}
-+
-+static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_disconn_req *req = (l2cap_disconn_req *) data;
-+ l2cap_disconn_rsp rsp;
-+ __u16 dcid, scid;
-+ struct sock *sk;
-+
-+ scid = __le16_to_cpu(req->scid);
-+ dcid = __le16_to_cpu(req->dcid);
-+
-+ BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-+ return 0;
-+
-+ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
-+
-+ sk->shutdown = SHUTDOWN_MASK;
-+
-+ l2cap_chan_del(sk, ECONNRESET);
-+ bh_unlock_sock(sk);
-+
-+ l2cap_sock_kill(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
-+ __u16 dcid, scid;
-+ struct sock *sk;
-+
-+ scid = __le16_to_cpu(rsp->scid);
-+ dcid = __le16_to_cpu(rsp->dcid);
-+
-+ BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+ return 0;
-+ l2cap_chan_del(sk, 0);
-+ bh_unlock_sock(sk);
-+
-+ l2cap_sock_kill(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_information_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, u8 *data)
-+{
-+ l2cap_info_req *req = (l2cap_info_req *) data;
-+ l2cap_info_rsp rsp;
-+ u16 type;
-+
-+ type = __le16_to_cpu(req->type);
-+
-+ BT_DBG("type 0x%4.4x", type);
-+
-+ rsp.type = __cpu_to_le16(type);
-+ rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
-+ return 0;
-+}
-+
-+static inline int l2cap_information_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, u8 *data)
-+{
-+ l2cap_info_rsp *rsp = (l2cap_info_rsp *) data;
-+ u16 type, result;
-+
-+ type = __le16_to_cpu(rsp->type);
-+ result = __le16_to_cpu(rsp->result);
-+
-+ BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
-+
-+ return 0;
-+}
-+
-+static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+ __u8 *data = skb->data;
-+ int len = skb->len;
-+ l2cap_cmd_hdr cmd;
-+ int err = 0;
-+
-+ l2cap_raw_recv(conn, skb);
-+
-+ while (len >= L2CAP_CMD_HDR_SIZE) {
-+ memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-+ data += L2CAP_CMD_HDR_SIZE;
-+ len -= L2CAP_CMD_HDR_SIZE;
-+
-+ cmd.len = __le16_to_cpu(cmd.len);
-+
-+ BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
-+
-+ if (cmd.len > len || !cmd.ident) {
-+ BT_DBG("corrupted command");
-+ break;
-+ }
-+
-+ switch (cmd.code) {
-+ case L2CAP_COMMAND_REJ:
-+ /* FIXME: We should process this */
-+ break;
-+
-+ case L2CAP_CONN_REQ:
-+ err = l2cap_connect_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_CONN_RSP:
-+ err = l2cap_connect_rsp(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_CONF_REQ:
-+ err = l2cap_config_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_CONF_RSP:
-+ err = l2cap_config_rsp(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_DISCONN_REQ:
-+ err = l2cap_disconnect_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_DISCONN_RSP:
-+ err = l2cap_disconnect_rsp(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_ECHO_REQ:
-+ l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
-+ break;
-+
-+ case L2CAP_ECHO_RSP:
-+ break;
-+
-+ case L2CAP_INFO_REQ:
-+ err = l2cap_information_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_INFO_RSP:
-+ err = l2cap_information_rsp(conn, &cmd, data);
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown signaling command 0x%2.2x", cmd.code);
-+ err = -EINVAL;
-+ break;
-+ };
-+
-+ if (err) {
-+ l2cap_cmd_rej rej;
-+ BT_DBG("error %d", err);
-+
-+ /* FIXME: Map err to a valid reason */
-+ rej.reason = __cpu_to_le16(0);
-+ l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
-+ }
-+
-+ data += cmd.len;
-+ len -= cmd.len;
-+ }
-+
-+ kfree_skb(skb);
-+}
-+
-+static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
-+{
-+ struct sock *sk;
-+
-+ sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
-+ if (!sk) {
-+ BT_DBG("unknown cid 0x%4.4x", cid);
-+ goto drop;
-+ }
-+
-+ BT_DBG("sk %p, len %d", sk, skb->len);
-+
-+ if (sk->state != BT_CONNECTED)
-+ goto drop;
-+
-+ if (l2cap_pi(sk)->imtu < skb->len)
-+ goto drop;
-+
-+ /* If socket recv buffers overflows we drop data here
-+ * which is *bad* because L2CAP has to be reliable.
-+ * But we don't have any other choice. L2CAP doesn't
-+ * provide flow control mechanism */
-+
-+ if (!sock_queue_rcv_skb(sk, skb))
-+ goto done;
-+
-+drop:
-+ kfree_skb(skb);
-+
-+done:
-+ if (sk) bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
-+{
-+ struct sock *sk;
-+
-+ sk = l2cap_get_sock_by_psm(0, psm, conn->src);
-+ if (!sk)
-+ goto drop;
-+
-+ BT_DBG("sk %p, len %d", sk, skb->len);
-+
-+ if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
-+ goto drop;
-+
-+ if (l2cap_pi(sk)->imtu < skb->len)
-+ goto drop;
-+
-+ if (!sock_queue_rcv_skb(sk, skb))
-+ goto done;
-+
-+drop:
-+ kfree_skb(skb);
-+
-+done:
-+ if (sk) bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+ l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-+ __u16 cid, psm, len;
-+
-+ skb_pull(skb, L2CAP_HDR_SIZE);
-+ cid = __le16_to_cpu(lh->cid);
-+ len = __le16_to_cpu(lh->len);
-+
-+ BT_DBG("len %d, cid 0x%4.4x", len, cid);
-+
-+ switch (cid) {
-+ case 0x0001:
-+ l2cap_sig_channel(conn, skb);
-+ break;
-+
-+ case 0x0002:
-+ psm = get_unaligned((__u16 *) skb->data);
-+ skb_pull(skb, 2);
-+ l2cap_conless_channel(conn, psm, skb);
-+ break;
-+
-+ default:
-+ l2cap_data_channel(conn, cid, skb);
-+ break;
-+ }
-+}
-+
-+/* ------------ L2CAP interface with lower layer (HCI) ------------- */
-+
-+static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+ int exact = 0, lm1 = 0, lm2 = 0;
-+ register struct sock *sk;
-+
-+ if (type != ACL_LINK)
-+ return 0;
-+
-+ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-+
-+ /* Find listening sockets and check their link_mode */
-+ read_lock(&l2cap_sk_list.lock);
-+ for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+ if (sk->state != BT_LISTEN)
-+ continue;
-+
-+ if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) {
-+ lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
-+ exact++;
-+ } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
-+ }
-+ read_unlock(&l2cap_sk_list.lock);
-+
-+ return exact ? lm1 : lm2;
-+}
-+
-+static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-+
-+ if (hcon->type != ACL_LINK)
-+ return 0;
-+
-+ if (!status) {
-+ struct l2cap_conn *conn;
-+
-+ conn = l2cap_conn_add(hcon, status);
-+ if (conn)
-+ l2cap_conn_ready(conn);
-+ } else
-+ l2cap_conn_del(hcon, bterr(status));
-+
-+ return 0;
-+}
-+
-+static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason)
-+{
-+ BT_DBG("hcon %p reason %d", hcon, reason);
-+
-+ if (hcon->type != ACL_LINK)
-+ return 0;
-+
-+ l2cap_conn_del(hcon, bterr(reason));
-+ return 0;
-+}
-+
-+static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ struct l2cap_chan_list *l;
-+ struct l2cap_conn *conn;
-+ l2cap_conn_rsp rsp;
-+ struct sock *sk;
-+ int result;
-+
-+ if (!(conn = hcon->l2cap_data))
-+ return 0;
-+ l = &conn->chan_list;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ bh_lock_sock(sk);
-+
-+ if (sk->state != BT_CONNECT2 ||
-+ (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) {
-+ bh_unlock_sock(sk);
-+ continue;
-+ }
-+
-+ if (!status) {
-+ sk->state = BT_CONFIG;
-+ result = 0;
-+ } else {
-+ sk->state = BT_DISCONN;
-+ l2cap_sock_set_timer(sk, HZ/10);
-+ result = L2CAP_CR_SEC_BLOCK;
-+ }
-+
-+ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ rsp.result = __cpu_to_le16(result);
-+ rsp.status = __cpu_to_le16(0);
-+ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
-+ L2CAP_CONN_RSP_SIZE, &rsp);
-+
-+ bh_unlock_sock(sk);
-+ }
-+
-+ read_unlock(&l->lock);
-+ return 0;
-+}
-+
-+static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ struct l2cap_chan_list *l;
-+ struct l2cap_conn *conn;
-+ l2cap_conn_rsp rsp;
-+ struct sock *sk;
-+ int result;
-+
-+ if (!(conn = hcon->l2cap_data))
-+ return 0;
-+ l = &conn->chan_list;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ bh_lock_sock(sk);
-+
-+ if (sk->state != BT_CONNECT2) {
-+ bh_unlock_sock(sk);
-+ continue;
-+ }
-+
-+ if (!status) {
-+ sk->state = BT_CONFIG;
-+ result = 0;
-+ } else {
-+ sk->state = BT_DISCONN;
-+ l2cap_sock_set_timer(sk, HZ/10);
-+ result = L2CAP_CR_SEC_BLOCK;
-+ }
-+
-+ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ rsp.result = __cpu_to_le16(result);
-+ rsp.status = __cpu_to_le16(0);
-+ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
-+ L2CAP_CONN_RSP_SIZE, &rsp);
-+
-+ bh_unlock_sock(sk);
-+ }
-+
-+ read_unlock(&l->lock);
-+ return 0;
-+}
-+
-+static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags)
-+{
-+ struct l2cap_conn *conn = hcon->l2cap_data;
-+
-+ if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
-+ goto drop;
-+
-+ BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
-+
-+ if (flags & ACL_START) {
-+ l2cap_hdr *hdr;
-+ int len;
-+
-+ if (conn->rx_len) {
-+ BT_ERR("Unexpected start frame (len %d)", skb->len);
-+ kfree_skb(conn->rx_skb);
-+ conn->rx_skb = NULL;
-+ conn->rx_len = 0;
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ }
-+
-+ if (skb->len < 2) {
-+ BT_ERR("Frame is too short (len %d)", skb->len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ hdr = (l2cap_hdr *) skb->data;
-+ len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
-+
-+ if (len == skb->len) {
-+ /* Complete frame received */
-+ l2cap_recv_frame(conn, skb);
-+ return 0;
-+ }
-+
-+ BT_DBG("Start: total len %d, frag len %d", len, skb->len);
-+
-+ if (skb->len > len) {
-+ BT_ERR("Frame is too long (len %d, expected len %d)",
-+ skb->len, len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ /* Allocate skb for the complete frame including header */
-+ conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+ if (!conn->rx_skb)
-+ goto drop;
-+
-+ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-+ conn->rx_len = len - skb->len;
-+ } else {
-+ BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
-+
-+ if (!conn->rx_len) {
-+ BT_ERR("Unexpected continuation frame (len %d)", skb->len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ if (skb->len > conn->rx_len) {
-+ BT_ERR("Fragment is too long (len %d, expected %d)",
-+ skb->len, conn->rx_len);
-+ kfree_skb(conn->rx_skb);
-+ conn->rx_skb = NULL;
-+ conn->rx_len = 0;
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-+ conn->rx_len -= skb->len;
-+
-+ if (!conn->rx_len) {
-+ /* Complete frame received */
-+ l2cap_recv_frame(conn, conn->rx_skb);
-+ conn->rx_skb = NULL;
-+ }
-+ }
-+
-+drop:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+/* ----- Proc fs support ------ */
-+static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
-+{
-+ struct l2cap_pinfo *pi;
-+ struct sock *sk;
-+ char *ptr = buf;
-+
-+ read_lock_bh(&list->lock);
-+
-+ for (sk = list->head; sk; sk = sk->next) {
-+ pi = l2cap_pi(sk);
-+ ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
-+ pi->link_mode);
-+ }
-+
-+ read_unlock_bh(&list->lock);
-+
-+ ptr += sprintf(ptr, "\n");
-+ return ptr - buf;
-+}
-+
-+static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+ char *ptr = buf;
-+ int len;
-+
-+ BT_DBG("count %d, offset %ld", count, offset);
-+
-+ ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
-+ len = ptr - buf;
-+
-+ if (len <= count + offset)
-+ *eof = 1;
-+
-+ *start = buf + offset;
-+ len -= offset;
-+
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+
-+static struct proto_ops l2cap_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: l2cap_sock_release,
-+ bind: l2cap_sock_bind,
-+ connect: l2cap_sock_connect,
-+ listen: l2cap_sock_listen,
-+ accept: l2cap_sock_accept,
-+ getname: l2cap_sock_getname,
-+ sendmsg: l2cap_sock_sendmsg,
-+ recvmsg: bluez_sock_recvmsg,
-+ poll: bluez_sock_poll,
-+ socketpair: sock_no_socketpair,
-+ ioctl: sock_no_ioctl,
-+ shutdown: l2cap_sock_shutdown,
-+ setsockopt: l2cap_sock_setsockopt,
-+ getsockopt: l2cap_sock_getsockopt,
-+ mmap: sock_no_mmap
-+};
-+
-+static struct net_proto_family l2cap_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: l2cap_sock_create
-+};
-+
-+static struct hci_proto l2cap_hci_proto = {
-+ name: "L2CAP",
-+ id: HCI_PROTO_L2CAP,
-+ connect_ind: l2cap_connect_ind,
-+ connect_cfm: l2cap_connect_cfm,
-+ disconn_ind: l2cap_disconn_ind,
-+ recv_acldata: l2cap_recv_acldata,
-+ auth_cfm: l2cap_auth_cfm,
-+ encrypt_cfm: l2cap_encrypt_cfm
-+};
-+
-+int __init l2cap_init(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
-+ BT_ERR("Can't register L2CAP socket");
-+ return err;
-+ }
-+
-+ if ((err = hci_register_proto(&l2cap_hci_proto))) {
-+ BT_ERR("Can't register L2CAP protocol");
-+ return err;
-+ }
-+
-+ create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
-+
-+ BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ return 0;
-+}
-+
-+void l2cap_cleanup(void)
-+{
-+ remove_proc_entry("bluetooth/l2cap", NULL);
-+
-+ /* Unregister socket and protocol */
-+ if (bluez_sock_unregister(BTPROTO_L2CAP))
-+ BT_ERR("Can't unregister L2CAP socket");
-+
-+ if (hci_unregister_proto(&l2cap_hci_proto))
-+ BT_ERR("Can't unregister L2CAP protocol");
-+}
-+
-+void l2cap_load(void)
-+{
-+ /* Dummy function to trigger automatic L2CAP module loading by
-+ other modules that use L2CAP sockets but do not use any other
-+ symbols from it. */
-+ return;
-+}
-+
-+EXPORT_SYMBOL(l2cap_load);
-+
-+module_init(l2cap_init);
-+module_exit(l2cap_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/l2cap_core.c linux-2.4.18-mh15/net/bluetooth/l2cap_core.c
---- linux-2.4.18/net/bluetooth/l2cap_core.c 2001-09-30 21:26:08.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/l2cap_core.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,2316 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * BlueZ L2CAP core and sockets.
-- *
-- * $Id$
-- */
--#define VERSION "1.1"
--
--#include <linux/config.h>
--#include <linux/module.h>
--
--#include <linux/types.h>
--#include <linux/errno.h>
--#include <linux/kernel.h>
--#include <linux/major.h>
--#include <linux/sched.h>
--#include <linux/slab.h>
--#include <linux/poll.h>
--#include <linux/fcntl.h>
--#include <linux/init.h>
--#include <linux/skbuff.h>
--#include <linux/interrupt.h>
--#include <linux/socket.h>
--#include <linux/skbuff.h>
--#include <linux/proc_fs.h>
--#include <linux/list.h>
--#include <net/sock.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/l2cap.h>
--#include <net/bluetooth/l2cap_core.h>
--
--#ifndef L2CAP_DEBUG
--#undef DBG
--#define DBG( A... )
--#endif
--
--struct proto_ops l2cap_sock_ops;
--
--struct bluez_sock_list l2cap_sk_list = {
-- lock: RW_LOCK_UNLOCKED
--};
--
--struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
--rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
--
--static int l2cap_conn_del(struct l2cap_conn *conn, int err);
--
--static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
--static void l2cap_chan_del(struct sock *sk, int err);
--static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
--
--static void l2cap_sock_close(struct sock *sk);
--static void l2cap_sock_kill(struct sock *sk);
--
--static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
--static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
--
--/* -------- L2CAP interfaces & routing --------- */
--/* Add/delete L2CAP interface.
-- * Must be called with locked rt_lock
-- */
--
--static void l2cap_iff_add(struct hci_dev *hdev)
--{
-- struct l2cap_iff *iff;
--
-- DBG("%s", hdev->name);
--
-- DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
--
-- /* Allocate new interface and lock HCI device */
-- if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
-- ERR("Can't allocate new interface %s", hdev->name);
-- return;
-- }
-- memset(iff, 0, sizeof(struct l2cap_iff));
--
-- hci_dev_hold(hdev);
-- hdev->l2cap_data = iff;
-- iff->hdev = hdev;
-- iff->mtu = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
-- iff->bdaddr = &hdev->bdaddr;
--
-- spin_lock_init(&iff->lock);
-- INIT_LIST_HEAD(&iff->conn_list);
--
-- list_add(&iff->list, &l2cap_iff_list);
--}
--
--static void l2cap_iff_del(struct hci_dev *hdev)
--{
-- struct l2cap_iff *iff;
--
-- if (!(iff = hdev->l2cap_data))
-- return;
--
-- DBG("%s iff %p", hdev->name, iff);
--
-- list_del(&iff->list);
--
-- l2cap_iff_lock(iff);
--
-- /* Drop connections */
-- while (!list_empty(&iff->conn_list)) {
-- struct l2cap_conn *c;
--
-- c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
-- l2cap_conn_del(c, ENODEV);
-- }
--
-- l2cap_iff_unlock(iff);
--
-- /* Unlock HCI device */
-- hdev->l2cap_data = NULL;
-- hci_dev_put(hdev);
--
-- kfree(iff);
--}
--
--/* Get route. Returns L2CAP interface.
-- * Must be called with locked rt_lock
-- */
--static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
--{
-- struct list_head *p;
-- int use_src;
--
-- DBG("%s -> %s", batostr(src), batostr(dst));
--
-- use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
--
-- /* Simple routing:
-- * No source address - find interface with bdaddr != dst
-- * Source address - find interface with bdaddr == src
-- */
--
-- list_for_each(p, &l2cap_iff_list) {
-- struct l2cap_iff *iff;
--
-- iff = list_entry(p, struct l2cap_iff, list);
--
-- if (use_src && !bacmp(iff->bdaddr, src))
-- return iff;
-- else if (bacmp(iff->bdaddr, dst))
-- return iff;
-- }
-- return NULL;
--}
--
--/* ----- L2CAP timers ------ */
--static void l2cap_sock_timeout(unsigned long arg)
--{
-- struct sock *sk = (struct sock *) arg;
--
-- DBG("sock %p state %d", sk, sk->state);
--
-- bh_lock_sock(sk);
-- switch (sk->state) {
-- case BT_DISCONN:
-- l2cap_chan_del(sk, ETIMEDOUT);
-- break;
--
-- default:
-- sk->err = ETIMEDOUT;
-- sk->state_change(sk);
-- break;
-- };
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
-- sock_put(sk);
--}
--
--static void l2cap_sock_set_timer(struct sock *sk, long timeout)
--{
-- DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
--
-- if (!mod_timer(&sk->timer, jiffies + timeout))
-- sock_hold(sk);
--}
--
--static void l2cap_sock_clear_timer(struct sock *sk)
--{
-- DBG("sock %p state %d", sk, sk->state);
--
-- if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-- __sock_put(sk);
--}
--
--static void l2cap_sock_init_timer(struct sock *sk)
--{
-- init_timer(&sk->timer);
-- sk->timer.function = l2cap_sock_timeout;
-- sk->timer.data = (unsigned long)sk;
--}
--
--static void l2cap_conn_timeout(unsigned long arg)
--{
-- struct l2cap_conn *conn = (void *)arg;
--
-- DBG("conn %p state %d", conn, conn->state);
--
-- if (conn->state == BT_CONNECTED) {
-- hci_disconnect(conn->hconn, 0x13);
-- }
--
-- return;
--}
--
--static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
--{
-- DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
--
-- mod_timer(&conn->timer, jiffies + timeout);
--}
--
--static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
--{
-- DBG("conn %p state %d", conn, conn->state);
--
-- del_timer(&conn->timer);
--}
--
--static void l2cap_conn_init_timer(struct l2cap_conn *conn)
--{
-- init_timer(&conn->timer);
-- conn->timer.function = l2cap_conn_timeout;
-- conn->timer.data = (unsigned long)conn;
--}
--
--/* -------- L2CAP connections --------- */
--/* Add new connection to the interface.
-- * Interface must be locked
-- */
--static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
--{
-- struct l2cap_conn *conn;
-- bdaddr_t *src = iff->bdaddr;
--
-- if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
-- return NULL;
--
-- memset(conn, 0, sizeof(struct l2cap_conn));
--
-- conn->state = BT_OPEN;
-- conn->iff = iff;
-- bacpy(&conn->src, src);
-- bacpy(&conn->dst, dst);
--
-- spin_lock_init(&conn->lock);
-- conn->chan_list.lock = RW_LOCK_UNLOCKED;
--
-- l2cap_conn_init_timer(conn);
--
-- __l2cap_conn_link(iff, conn);
--
-- DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
--
-- MOD_INC_USE_COUNT;
--
-- return conn;
--}
--
--/* Delete connection on the interface.
-- * Interface must be locked
-- */
--static int l2cap_conn_del(struct l2cap_conn *conn, int err)
--{
-- struct sock *sk;
--
-- DBG("conn %p, state %d, err %d", conn, conn->state, err);
--
-- l2cap_conn_clear_timer(conn);
-- __l2cap_conn_unlink(conn->iff, conn);
--
-- conn->state = BT_CLOSED;
--
-- if (conn->rx_skb)
-- kfree_skb(conn->rx_skb);
--
-- /* Kill channels */
-- while ((sk = conn->chan_list.head)) {
-- bh_lock_sock(sk);
-- l2cap_sock_clear_timer(sk);
-- l2cap_chan_del(sk, err);
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
-- }
--
-- kfree(conn);
--
-- MOD_DEC_USE_COUNT;
-- return 0;
--}
--
--static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
--{
-- struct list_head *p;
--
-- list_for_each(p, &iff->conn_list) {
-- struct l2cap_conn *c;
--
-- c = list_entry(p, struct l2cap_conn, list);
-- if (!bacmp(&c->dst, dst))
-- return c;
-- }
-- return NULL;
--}
--
--int l2cap_connect(struct sock *sk)
--{
-- bdaddr_t *src = &l2cap_pi(sk)->src;
-- bdaddr_t *dst = &l2cap_pi(sk)->dst;
-- struct l2cap_conn *conn;
-- struct l2cap_iff *iff;
-- int err = 0;
--
-- DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
--
-- read_lock_bh(&l2cap_rt_lock);
--
-- /* Get route to remote BD address */
-- if (!(iff = l2cap_get_route(src, dst))) {
-- err = -EHOSTUNREACH;
-- goto done;
-- }
--
-- /* Update source addr of the socket */
-- bacpy(src, iff->bdaddr);
--
-- l2cap_iff_lock(iff);
--
-- if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
-- /* Connection doesn't exist */
-- if (!(conn = l2cap_conn_add(iff, dst))) {
-- l2cap_iff_unlock(iff);
-- err = -ENOMEM;
-- goto done;
-- }
-- conn->out = 1;
-- }
--
-- l2cap_iff_unlock(iff);
--
-- l2cap_chan_add(conn, sk, NULL);
--
-- sk->state = BT_CONNECT;
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
--
-- switch (conn->state) {
-- case BT_CONNECTED:
-- if (sk->type == SOCK_SEQPACKET) {
-- l2cap_conn_req req;
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- req.psm = l2cap_pi(sk)->psm;
-- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-- } else {
-- l2cap_sock_clear_timer(sk);
-- sk->state = BT_CONNECTED;
-- }
-- break;
--
-- case BT_CONNECT:
-- break;
--
-- default:
-- /* Create ACL connection */
-- conn->state = BT_CONNECT;
-- hci_connect(iff->hdev, dst);
-- break;
-- };
--
--done:
-- read_unlock_bh(&l2cap_rt_lock);
-- return err;
--}
--
--/* ------ Channel queues for listening sockets ------ */
--void l2cap_accept_queue(struct sock *parent, struct sock *sk)
--{
-- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
--
-- DBG("parent %p, sk %p", parent, sk);
--
-- sock_hold(sk);
-- l2cap_pi(sk)->parent = parent;
-- l2cap_pi(sk)->next_q = NULL;
--
-- if (!q->head) {
-- q->head = q->tail = sk;
-- } else {
-- struct sock *tail = q->tail;
--
-- l2cap_pi(sk)->prev_q = tail;
-- l2cap_pi(tail)->next_q = sk;
-- q->tail = sk;
-- }
--
-- parent->ack_backlog++;
--}
--
--void l2cap_accept_unlink(struct sock *sk)
--{
-- struct sock *parent = l2cap_pi(sk)->parent;
-- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-- struct sock *next, *prev;
--
-- DBG("sk %p", sk);
--
-- next = l2cap_pi(sk)->next_q;
-- prev = l2cap_pi(sk)->prev_q;
--
-- if (sk == q->head)
-- q->head = next;
-- if (sk == q->tail)
-- q->tail = prev;
--
-- if (next)
-- l2cap_pi(next)->prev_q = prev;
-- if (prev)
-- l2cap_pi(prev)->next_q = next;
--
-- l2cap_pi(sk)->parent = NULL;
--
-- parent->ack_backlog--;
-- __sock_put(sk);
--}
--
--/* Get next connected channel in queue. */
--struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
--{
-- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-- struct sock *sk;
--
-- for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
-- if (!state || sk->state == state) {
-- l2cap_accept_unlink(sk);
-- break;
-- }
-- }
--
-- DBG("parent %p, sk %p", parent, sk);
--
-- return sk;
--}
--
--/* -------- Socket interface ---------- */
--static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
--{
-- bdaddr_t *src = &addr->l2_bdaddr;
-- __u16 psm = addr->l2_psm;
-- struct sock *sk;
--
-- for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-- if (l2cap_pi(sk)->psm == psm &&
-- !bacmp(&l2cap_pi(sk)->src, src))
-- break;
-- }
--
-- return sk;
--}
--
--/* Find socket listening on psm and source bdaddr.
-- * Returns closest match.
-- */
--static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
--{
-- struct sock *sk, *sk1 = NULL;
--
-- read_lock(&l2cap_sk_list.lock);
--
-- for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-- struct l2cap_pinfo *pi;
--
-- if (sk->state != BT_LISTEN)
-- continue;
--
-- pi = l2cap_pi(sk);
--
-- if (pi->psm == psm) {
-- /* Exact match. */
-- if (!bacmp(&pi->src, src))
-- break;
--
-- /* Closest match */
-- if (!bacmp(&pi->src, BDADDR_ANY))
-- sk1 = sk;
-- }
-- }
--
-- read_unlock(&l2cap_sk_list.lock);
--
-- return sk ? sk : sk1;
--}
--
--static void l2cap_sock_destruct(struct sock *sk)
--{
-- DBG("sk %p", sk);
--
-- skb_queue_purge(&sk->receive_queue);
-- skb_queue_purge(&sk->write_queue);
--
-- MOD_DEC_USE_COUNT;
--}
--
--static void l2cap_sock_cleanup_listen(struct sock *parent)
--{
-- struct sock *sk;
--
-- DBG("parent %p", parent);
--
-- /* Close not yet accepted channels */
-- while ((sk = l2cap_accept_dequeue(parent, 0)))
-- l2cap_sock_close(sk);
--
-- parent->state = BT_CLOSED;
-- parent->zapped = 1;
--}
--
--/* Kill socket (only if zapped and orphan)
-- * Must be called on unlocked socket.
-- */
--static void l2cap_sock_kill(struct sock *sk)
--{
-- if (!sk->zapped || sk->socket)
-- return;
--
-- DBG("sk %p state %d", sk, sk->state);
--
-- /* Kill poor orphan */
-- bluez_sock_unlink(&l2cap_sk_list, sk);
-- sk->dead = 1;
-- sock_put(sk);
--}
--
--/* Close socket.
-- * Must be called on unlocked socket.
-- */
--static void l2cap_sock_close(struct sock *sk)
--{
-- struct l2cap_conn *conn;
--
-- l2cap_sock_clear_timer(sk);
--
-- lock_sock(sk);
--
-- conn = l2cap_pi(sk)->conn;
--
-- DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
--
-- switch (sk->state) {
-- case BT_LISTEN:
-- l2cap_sock_cleanup_listen(sk);
-- break;
--
-- case BT_CONNECTED:
-- case BT_CONFIG:
-- if (sk->type == SOCK_SEQPACKET) {
-- l2cap_disconn_req req;
--
-- sk->state = BT_DISCONN;
--
-- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
--
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
-- } else {
-- l2cap_chan_del(sk, ECONNRESET);
-- }
-- break;
--
-- case BT_CONNECT:
-- case BT_DISCONN:
-- l2cap_chan_del(sk, ECONNRESET);
-- break;
--
-- default:
-- sk->zapped = 1;
-- break;
-- };
--
-- release_sock(sk);
--
-- l2cap_sock_kill(sk);
--}
--
--static void l2cap_sock_init(struct sock *sk, struct sock *parent)
--{
-- struct l2cap_pinfo *pi = l2cap_pi(sk);
--
-- DBG("sk %p", sk);
--
-- if (parent) {
-- sk->type = parent->type;
--
-- pi->imtu = l2cap_pi(parent)->imtu;
-- pi->omtu = l2cap_pi(parent)->omtu;
-- } else {
-- pi->imtu = L2CAP_DEFAULT_MTU;
-- pi->omtu = 0;
-- }
--
-- /* Default config options */
-- pi->conf_mtu = L2CAP_DEFAULT_MTU;
-- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
--}
--
--static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
--{
-- struct sock *sk;
--
-- if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-- return NULL;
--
-- sock_init_data(sock, sk);
--
-- sk->zapped = 0;
--
-- sk->destruct = l2cap_sock_destruct;
-- sk->sndtimeo = L2CAP_CONN_TIMEOUT;
--
-- sk->protocol = proto;
-- sk->state = BT_OPEN;
--
-- l2cap_sock_init_timer(sk);
--
-- bluez_sock_link(&l2cap_sk_list, sk);
--
-- MOD_INC_USE_COUNT;
--
-- return sk;
--}
--
--static int l2cap_sock_create(struct socket *sock, int protocol)
--{
-- struct sock *sk;
--
-- DBG("sock %p", sock);
--
-- sock->state = SS_UNCONNECTED;
--
-- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
-- return -ESOCKTNOSUPPORT;
--
-- sock->ops = &l2cap_sock_ops;
--
-- if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
-- return -ENOMEM;
--
-- l2cap_sock_init(sk, NULL);
--
-- return 0;
--}
--
--static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
--{
-- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
--
-- if (!addr || addr->sa_family != AF_BLUETOOTH)
-- return -EINVAL;
--
-- lock_sock(sk);
--
-- if (sk->state != BT_OPEN) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- write_lock(&l2cap_sk_list.lock);
--
-- if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
-- err = -EADDRINUSE;
-- goto unlock;
-- }
--
-- /* Save source address */
-- bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
-- l2cap_pi(sk)->psm = la->l2_psm;
-- sk->state = BT_BOUND;
--
--unlock:
-- write_unlock(&l2cap_sk_list.lock);
--
--done:
-- release_sock(sk);
--
-- return err;
--}
--
--static int l2cap_sock_w4_connect(struct sock *sk, int flags)
--{
-- DECLARE_WAITQUEUE(wait, current);
-- long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
-- int err = 0;
--
-- DBG("sk %p", sk);
--
-- add_wait_queue(sk->sleep, &wait);
-- current->state = TASK_INTERRUPTIBLE;
--
-- while (sk->state != BT_CONNECTED) {
-- if (!timeo) {
-- err = -EAGAIN;
-- break;
-- }
--
-- release_sock(sk);
-- timeo = schedule_timeout(timeo);
-- lock_sock(sk);
--
-- err = 0;
-- if (sk->state == BT_CONNECTED)
-- break;
--
-- if (sk->err) {
-- err = sock_error(sk);
-- break;
-- }
--
-- if (signal_pending(current)) {
-- err = sock_intr_errno(timeo);
-- break;
-- }
-- }
-- current->state = TASK_RUNNING;
-- remove_wait_queue(sk->sleep, &wait);
--
-- return err;
--}
--
--static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
--{
-- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- lock_sock(sk);
--
-- DBG("sk %p", sk);
--
-- if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-- err = -EINVAL;
-- goto done;
-- }
--
-- if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
-- err = -EINVAL;
-- goto done;
-- }
--
-- /* Set destination address and psm */
-- bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
-- l2cap_pi(sk)->psm = la->l2_psm;
--
-- if ((err = l2cap_connect(sk)))
-- goto done;
--
-- err = l2cap_sock_w4_connect(sk, flags);
--
--done:
-- release_sock(sk);
-- return err;
--}
--
--int l2cap_sock_listen(struct socket *sock, int backlog)
--{
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- DBG("sk %p backlog %d", sk, backlog);
--
-- lock_sock(sk);
--
-- if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- if (!l2cap_pi(sk)->psm) {
-- err = -EINVAL;
-- goto done;
-- }
--
-- sk->max_ack_backlog = backlog;
-- sk->ack_backlog = 0;
-- sk->state = BT_LISTEN;
--
--done:
-- release_sock(sk);
-- return err;
--}
--
--int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
--{
-- DECLARE_WAITQUEUE(wait, current);
-- struct sock *sk = sock->sk, *ch;
-- long timeo;
-- int err = 0;
--
-- lock_sock(sk);
--
-- if (sk->state != BT_LISTEN) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
--
-- DBG("sk %p timeo %ld", sk, timeo);
--
-- /* Wait for an incoming connection. (wake-one). */
-- add_wait_queue_exclusive(sk->sleep, &wait);
-- current->state = TASK_INTERRUPTIBLE;
-- while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
-- if (!timeo) {
-- err = -EAGAIN;
-- break;
-- }
--
-- release_sock(sk);
-- timeo = schedule_timeout(timeo);
-- lock_sock(sk);
--
-- if (sk->state != BT_LISTEN) {
-- err = -EBADFD;
-- break;
-- }
--
-- if (signal_pending(current)) {
-- err = sock_intr_errno(timeo);
-- break;
-- }
-- }
-- current->state = TASK_RUNNING;
-- remove_wait_queue(sk->sleep, &wait);
--
-- if (err)
-- goto done;
--
-- sock_graft(ch, newsock);
-- newsock->state = SS_CONNECTED;
--
-- DBG("new socket %p", ch);
--
--done:
-- release_sock(sk);
--
-- return err;
--}
--
--static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
--{
-- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-- struct sock *sk = sock->sk;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- addr->sa_family = AF_BLUETOOTH;
-- *len = sizeof(struct sockaddr_l2);
--
-- if (peer)
-- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
-- else
-- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
--
-- la->l2_psm = l2cap_pi(sk)->psm;
--
-- return 0;
--}
--
--static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
--{
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- if (sk->err)
-- return sock_error(sk);
--
-- if (msg->msg_flags & MSG_OOB)
-- return -EOPNOTSUPP;
--
-- lock_sock(sk);
--
-- if (sk->state == BT_CONNECTED)
-- err = l2cap_chan_send(sk, msg, len);
-- else
-- err = -ENOTCONN;
--
-- release_sock(sk);
-- return err;
--}
--
--static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
--{
-- struct sock *sk = sock->sk;
-- int noblock = flags & MSG_DONTWAIT;
-- int copied, err;
-- struct sk_buff *skb;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- if (flags & (MSG_OOB))
-- return -EOPNOTSUPP;
--
-- if (sk->state == BT_CLOSED)
-- return 0;
--
-- if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
-- return err;
--
-- msg->msg_namelen = 0;
--
-- copied = skb->len;
-- if (len < copied) {
-- msg->msg_flags |= MSG_TRUNC;
-- copied = len;
-- }
--
-- skb->h.raw = skb->data;
-- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
--
-- skb_free_datagram(sk, skb);
--
-- return err ? : copied;
--}
--
--int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
--{
-- struct sock *sk = sock->sk;
-- struct l2cap_options opts;
-- int err = 0;
--
-- DBG("sk %p", sk);
--
-- lock_sock(sk);
--
-- switch (optname) {
-- case L2CAP_OPTIONS:
-- if (copy_from_user((char *)&opts, optval, optlen)) {
-- err = -EFAULT;
-- break;
-- }
-- l2cap_pi(sk)->imtu = opts.imtu;
-- l2cap_pi(sk)->omtu = opts.omtu;
-- break;
--
-- default:
-- err = -ENOPROTOOPT;
-- break;
-- };
--
-- release_sock(sk);
-- return err;
--}
--
--int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
--{
-- struct sock *sk = sock->sk;
-- struct l2cap_options opts;
-- struct l2cap_conninfo cinfo;
-- int len, err = 0;
--
-- if (get_user(len, optlen))
-- return -EFAULT;
--
-- lock_sock(sk);
--
-- switch (optname) {
-- case L2CAP_OPTIONS:
-- opts.imtu = l2cap_pi(sk)->imtu;
-- opts.omtu = l2cap_pi(sk)->omtu;
-- opts.flush_to = l2cap_pi(sk)->flush_to;
--
-- len = MIN(len, sizeof(opts));
-- if (copy_to_user(optval, (char *)&opts, len))
-- err = -EFAULT;
--
-- break;
--
-- case L2CAP_CONNINFO:
-- if (sk->state != BT_CONNECTED) {
-- err = -ENOTCONN;
-- break;
-- }
--
-- cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
--
-- len = MIN(len, sizeof(cinfo));
-- if (copy_to_user(optval, (char *)&cinfo, len))
-- err = -EFAULT;
--
-- break;
--
-- default:
-- err = -ENOPROTOOPT;
-- break;
-- };
--
-- release_sock(sk);
-- return err;
--}
--
--static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
--{
-- struct sock *sk = sock->sk;
-- struct l2cap_accept_q *aq;
-- unsigned int mask;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- poll_wait(file, sk->sleep, wait);
-- mask = 0;
--
-- if (sk->err || !skb_queue_empty(&sk->error_queue))
-- mask |= POLLERR;
--
-- if (sk->shutdown == SHUTDOWN_MASK)
-- mask |= POLLHUP;
--
-- aq = &l2cap_pi(sk)->accept_q;
-- if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
-- mask |= POLLIN | POLLRDNORM;
--
-- if (sk->state == BT_CLOSED)
-- mask |= POLLHUP;
--
-- if (sock_writeable(sk))
-- mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-- else
-- set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
--
-- return mask;
--}
--
--static int l2cap_sock_release(struct socket *sock)
--{
-- struct sock *sk = sock->sk;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- if (!sk)
-- return 0;
--
-- sock_orphan(sk);
--
-- l2cap_sock_close(sk);
--
-- return 0;
--}
--
--/* --------- L2CAP channels --------- */
--static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-- if (l2cap_pi(s)->dcid == cid)
-- break;
-- }
--
-- return s;
--}
--
--static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- read_lock(&l->lock);
-- s = __l2cap_get_chan_by_dcid(l, cid);
-- read_unlock(&l->lock);
--
-- return s;
--}
--
--static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-- if (l2cap_pi(s)->scid == cid)
-- break;
-- }
--
-- return s;
--}
--static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- read_lock(&l->lock);
-- s = __l2cap_get_chan_by_scid(l, cid);
-- read_unlock(&l->lock);
--
-- return s;
--}
--
--static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
--{
-- struct sock *s;
--
-- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-- if (l2cap_pi(s)->ident == ident)
-- break;
-- }
--
-- return s;
--}
--
--static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
--{
-- struct sock *s;
--
-- read_lock(&l->lock);
-- s = __l2cap_get_chan_by_ident(l, ident);
-- read_unlock(&l->lock);
--
-- return s;
--}
--
--static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
--{
-- __u16 cid = 0x0040;
--
-- for (; cid < 0xffff; cid++) {
-- if(!__l2cap_get_chan_by_scid(l, cid))
-- return cid;
-- }
--
-- return 0;
--}
--
--static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
--{
-- sock_hold(sk);
--
-- if (l->head)
-- l2cap_pi(l->head)->prev_c = sk;
--
-- l2cap_pi(sk)->next_c = l->head;
-- l2cap_pi(sk)->prev_c = NULL;
-- l->head = sk;
--}
--
--static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
--{
-- struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
--
-- write_lock(&l->lock);
-- if (sk == l->head)
-- l->head = next;
--
-- if (next)
-- l2cap_pi(next)->prev_c = prev;
-- if (prev)
-- l2cap_pi(prev)->next_c = next;
-- write_unlock(&l->lock);
--
-- __sock_put(sk);
--}
--
--static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
--
-- DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
--
-- l2cap_conn_clear_timer(conn);
--
-- atomic_inc(&conn->refcnt);
-- l2cap_pi(sk)->conn = conn;
--
-- if (sk->type == SOCK_SEQPACKET) {
-- /* Alloc CID for normal socket */
-- l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
-- } else {
-- /* Raw socket can send only signalling messages */
-- l2cap_pi(sk)->scid = 0x0001;
-- l2cap_pi(sk)->dcid = 0x0001;
-- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-- }
--
-- __l2cap_chan_link(l, sk);
--
-- if (parent)
-- l2cap_accept_queue(parent, sk);
--}
--
--static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
--
-- write_lock(&l->lock);
-- __l2cap_chan_add(conn, sk, parent);
-- write_unlock(&l->lock);
--}
--
--/* Delete channel.
-- * Must be called on the locked socket. */
--static void l2cap_chan_del(struct sock *sk, int err)
--{
-- struct l2cap_conn *conn;
-- struct sock *parent;
--
-- conn = l2cap_pi(sk)->conn;
-- parent = l2cap_pi(sk)->parent;
--
-- DBG("sk %p, conn %p, err %d", sk, conn, err);
--
-- if (parent) {
-- /* Unlink from parent accept queue */
-- bh_lock_sock(parent);
-- l2cap_accept_unlink(sk);
-- bh_unlock_sock(parent);
-- }
--
-- if (conn) {
-- long timeout;
--
-- /* Unlink from channel list */
-- l2cap_chan_unlink(&conn->chan_list, sk);
-- l2cap_pi(sk)->conn = NULL;
--
-- if (conn->out)
-- timeout = L2CAP_DISCONN_TIMEOUT;
-- else
-- timeout = L2CAP_CONN_IDLE_TIMEOUT;
--
-- if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
-- /* Schedule Baseband disconnect */
-- l2cap_conn_set_timer(conn, timeout);
-- }
-- }
--
-- sk->state = BT_CLOSED;
-- sk->err = err;
-- sk->state_change(sk);
--
-- sk->zapped = 1;
--}
--
--static void l2cap_conn_ready(struct l2cap_conn *conn)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
-- struct sock *sk;
--
-- DBG("conn %p", conn);
--
-- read_lock(&l->lock);
--
-- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-- bh_lock_sock(sk);
--
-- if (sk->type != SOCK_SEQPACKET) {
-- sk->state = BT_CONNECTED;
-- sk->state_change(sk);
-- l2cap_sock_clear_timer(sk);
-- } else if (sk->state == BT_CONNECT) {
-- l2cap_conn_req req;
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- req.psm = l2cap_pi(sk)->psm;
-- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
--
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
-- }
--
-- bh_unlock_sock(sk);
-- }
--
-- read_unlock(&l->lock);
--}
--
--static void l2cap_chan_ready(struct sock *sk)
--{
-- struct sock *parent = l2cap_pi(sk)->parent;
--
-- DBG("sk %p, parent %p", sk, parent);
--
-- l2cap_pi(sk)->conf_state = 0;
-- l2cap_sock_clear_timer(sk);
--
-- if (!parent) {
-- /* Outgoing channel.
-- * Wake up socket sleeping on connect.
-- */
-- sk->state = BT_CONNECTED;
-- sk->state_change(sk);
-- } else {
-- /* Incomming channel.
-- * Wake up socket sleeping on accept.
-- */
-- parent->data_ready(parent, 1);
-- }
--}
--
--/* Copy frame to all raw sockets on that connection */
--void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
-- struct sk_buff *nskb;
-- struct sock * sk;
--
-- DBG("conn %p", conn);
--
-- read_lock(&l->lock);
-- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-- if (sk->type != SOCK_RAW)
-- continue;
--
-- /* Don't send frame to the socket it came from */
-- if (skb->sk == sk)
-- continue;
--
-- if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
-- continue;
--
-- skb_queue_tail(&sk->receive_queue, nskb);
-- sk->data_ready(sk, nskb->len);
-- }
-- read_unlock(&l->lock);
--}
--
--static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
--{
-- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-- struct sk_buff *skb, **frag;
-- int err, size, count, sent=0;
-- l2cap_hdr *lh;
--
-- /* Check outgoing MTU */
-- if (len > l2cap_pi(sk)->omtu)
-- return -EINVAL;
--
-- DBG("sk %p len %d", sk, len);
--
-- /* First fragment (with L2CAP header) */
-- count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
-- size = L2CAP_HDR_SIZE + count;
-- if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
-- return err;
--
-- /* Create L2CAP header */
-- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-- lh->len = __cpu_to_le16(len);
-- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
--
-- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-- err = -EFAULT;
-- goto fail;
-- }
--
-- sent += count;
-- len -= count;
--
-- /* Continuation fragments (no L2CAP header) */
-- frag = &skb_shinfo(skb)->frag_list;
-- while (len) {
-- count = MIN(conn->iff->mtu, len);
--
-- *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
-- if (!*frag)
-- goto fail;
--
-- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
-- err = -EFAULT;
-- goto fail;
-- }
--
-- sent += count;
-- len -= count;
--
-- frag = &(*frag)->next;
-- }
--
-- if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
-- goto fail;
--
-- return sent;
--
--fail:
-- kfree_skb(skb);
-- return err;
--}
--
--/* --------- L2CAP signalling commands --------- */
--static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
--{
-- __u8 id;
--
-- /* Get next available identificator.
-- * 1 - 199 are used by kernel.
-- * 200 - 254 are used by utilities like l2ping, etc
-- */
--
-- spin_lock(&conn->lock);
--
-- if (++conn->tx_ident > 199)
-- conn->tx_ident = 1;
--
-- id = conn->tx_ident;
--
-- spin_unlock(&conn->lock);
--
-- return id;
--}
--
--static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
--{
-- struct sk_buff *skb;
-- l2cap_cmd_hdr *cmd;
-- l2cap_hdr *lh;
-- int size;
--
-- DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
--
-- size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
-- if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
-- return NULL;
--
-- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-- lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
-- lh->cid = __cpu_to_le16(0x0001);
--
-- cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
-- cmd->code = code;
-- cmd->ident = ident;
-- cmd->len = __cpu_to_le16(len);
--
-- if (len)
-- memcpy(skb_put(skb, len), data, len);
--
-- return skb;
--}
--
--static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
--{
-- struct sk_buff *skb;
-- __u8 ident;
--
-- DBG("code 0x%2.2x", code);
--
-- ident = l2cap_get_ident(conn);
-- if (!(skb = l2cap_build_cmd(code, ident, len, data)))
-- return -ENOMEM;
-- return hci_send_acl(conn->hconn, skb, 0);
--}
--
--static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
--{
-- struct sk_buff *skb;
--
-- DBG("code 0x%2.2x", code);
--
-- if (!(skb = l2cap_build_cmd(code, ident, len, data)))
-- return -ENOMEM;
-- return hci_send_acl(conn->hconn, skb, 0);
--}
--
--static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
--{
-- l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
-- int len;
--
-- *type = opt->type;
-- switch (opt->len) {
-- case 1:
-- *val = *((__u8 *) opt->val);
-- break;
--
-- case 2:
-- *val = __le16_to_cpu(*((__u16 *)opt->val));
-- break;
--
-- case 4:
-- *val = __le32_to_cpu(*((__u32 *)opt->val));
-- break;
--
-- default:
-- *val = 0L;
-- break;
-- };
--
-- DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
--
-- len = L2CAP_CONF_OPT_SIZE + opt->len;
--
-- *ptr += len;
--
-- return len;
--}
--
--static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
--{
-- __u8 type, hint; __u32 val;
-- __u8 *ptr = data;
--
-- DBG("sk %p len %d", sk, len);
--
-- while (len >= L2CAP_CONF_OPT_SIZE) {
-- len -= l2cap_get_conf_opt(&ptr, &type, &val);
--
-- hint = type & 0x80;
-- type &= 0x7f;
--
-- switch (type) {
-- case L2CAP_CONF_MTU:
-- l2cap_pi(sk)->conf_mtu = val;
-- break;
--
-- case L2CAP_CONF_FLUSH_TO:
-- l2cap_pi(sk)->flush_to = val;
-- break;
--
-- case L2CAP_CONF_QOS:
-- break;
--
-- default:
-- if (hint)
-- break;
--
-- /* FIXME: Reject unknon option */
-- break;
-- };
-- }
--}
--
--static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
--{
-- register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
--
-- DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
--
-- opt->type = type;
-- opt->len = len;
-- switch (len) {
-- case 1:
-- *((__u8 *) opt->val) = val;
-- break;
--
-- case 2:
-- *((__u16 *) opt->val) = __cpu_to_le16(val);
-- break;
--
-- case 4:
-- *((__u32 *) opt->val) = __cpu_to_le32(val);
-- break;
-- };
--
-- *ptr += L2CAP_CONF_OPT_SIZE + len;
--}
--
--static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
--{
-- struct l2cap_pinfo *pi = l2cap_pi(sk);
-- l2cap_conf_req *req = (l2cap_conf_req *) data;
-- __u8 *ptr = req->data;
--
-- DBG("sk %p", sk);
--
-- if (pi->imtu != L2CAP_DEFAULT_MTU)
-- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
--
-- /* FIXME. Need actual value of the flush timeout */
-- //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-- // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
--
-- req->dcid = __cpu_to_le16(pi->dcid);
-- req->flags = __cpu_to_le16(0);
--
-- return ptr - data;
--}
--
--static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
--{
-- struct l2cap_pinfo *pi = l2cap_pi(sk);
-- int result = 0;
--
-- /* Configure output options and let other side know
-- * which ones we don't like.
-- */
-- if (pi->conf_mtu < pi->omtu) {
-- l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
-- result = L2CAP_CONF_UNACCEPT;
-- } else {
-- pi->omtu = pi->conf_mtu;
-- }
--
-- DBG("sk %p result %d", sk, result);
-- return result;
--}
--
--static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
--{
-- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
-- __u8 *ptr = rsp->data;
--
-- DBG("sk %p complete %d", sk, result ? 1 : 0);
--
-- if (result)
-- *result = l2cap_conf_output(sk, &ptr);
--
-- rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- rsp->result = __cpu_to_le16(result ? *result : 0);
-- rsp->flags = __cpu_to_le16(0);
--
-- return ptr - data;
--}
--
--static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- struct l2cap_chan_list *list = &conn->chan_list;
-- l2cap_conn_req *req = (l2cap_conn_req *) data;
-- l2cap_conn_rsp rsp;
-- struct sock *sk, *parent;
--
-- __u16 scid = __le16_to_cpu(req->scid);
-- __u16 psm = req->psm;
--
-- DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
--
-- /* Check if we have socket listening on psm */
-- if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
-- goto reject;
--
-- bh_lock_sock(parent);
-- write_lock(&list->lock);
--
-- /* Check if we already have channel with that dcid */
-- if (__l2cap_get_chan_by_dcid(list, scid))
-- goto unlock;
--
-- /* Check for backlog size */
-- if (parent->ack_backlog > parent->max_ack_backlog)
-- goto unlock;
--
-- if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
-- goto unlock;
--
-- l2cap_sock_init(sk, parent);
--
-- bacpy(&l2cap_pi(sk)->src, &conn->src);
-- bacpy(&l2cap_pi(sk)->dst, &conn->dst);
-- l2cap_pi(sk)->psm = psm;
-- l2cap_pi(sk)->dcid = scid;
--
-- __l2cap_chan_add(conn, sk, parent);
-- sk->state = BT_CONFIG;
--
-- write_unlock(&list->lock);
-- bh_unlock_sock(parent);
--
-- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- rsp.result = __cpu_to_le16(0);
-- rsp.status = __cpu_to_le16(0);
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
--
-- return 0;
--
--unlock:
-- write_unlock(&list->lock);
-- bh_unlock_sock(parent);
--
--reject:
-- rsp.scid = __cpu_to_le16(scid);
-- rsp.dcid = __cpu_to_le16(0);
-- rsp.status = __cpu_to_le16(0);
-- rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
--
-- return 0;
--}
--
--static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
-- __u16 scid, dcid, result, status;
-- struct sock *sk;
--
-- scid = __le16_to_cpu(rsp->scid);
-- dcid = __le16_to_cpu(rsp->dcid);
-- result = __le16_to_cpu(rsp->result);
-- status = __le16_to_cpu(rsp->status);
--
-- DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
--
-- if (!result) {
-- char req[64];
--
-- sk->state = BT_CONFIG;
-- l2cap_pi(sk)->dcid = dcid;
-- l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
--
-- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-- } else {
-- l2cap_chan_del(sk, ECONNREFUSED);
-- }
--
-- bh_unlock_sock(sk);
-- return 0;
--}
--
--static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_conf_req * req = (l2cap_conf_req *) data;
-- __u16 dcid, flags;
-- __u8 rsp[64];
-- struct sock *sk;
-- int result;
--
-- dcid = __le16_to_cpu(req->dcid);
-- flags = __le16_to_cpu(req->flags);
--
-- DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
--
-- l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
--
-- if (flags & 0x01) {
-- /* Incomplete config. Send empty response. */
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
-- goto unlock;
-- }
--
-- /* Complete config. */
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
--
-- if (result)
-- goto unlock;
--
-- /* Output config done */
-- l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
--
-- if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
-- sk->state = BT_CONNECTED;
-- l2cap_chan_ready(sk);
-- } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
-- char req[64];
-- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-- }
--
--unlock:
-- bh_unlock_sock(sk);
--
-- return 0;
--}
--
--static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
-- __u16 scid, flags, result;
-- struct sock *sk;
-- int err = 0;
--
-- scid = __le16_to_cpu(rsp->scid);
-- flags = __le16_to_cpu(rsp->flags);
-- result = __le16_to_cpu(rsp->result);
--
-- DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
--
-- if (result) {
-- l2cap_disconn_req req;
--
-- /* They didn't like our options. Well... we do not negotiate.
-- * Close channel.
-- */
-- sk->state = BT_DISCONN;
--
-- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
--
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
-- goto done;
-- }
--
-- if (flags & 0x01)
-- goto done;
--
-- /* Input config done */
-- l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
--
-- if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
-- sk->state = BT_CONNECTED;
-- l2cap_chan_ready(sk);
-- }
--
--done:
-- bh_unlock_sock(sk);
--
-- return err;
--}
--
--static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_disconn_req *req = (l2cap_disconn_req *) data;
-- l2cap_disconn_rsp rsp;
-- __u16 dcid, scid;
-- struct sock *sk;
--
-- scid = __le16_to_cpu(req->scid);
-- dcid = __le16_to_cpu(req->dcid);
--
-- DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-- return 0;
--
-- bh_lock_sock(sk);
--
-- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
--
-- l2cap_chan_del(sk, ECONNRESET);
--
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
--
-- return 0;
--}
--
--static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
-- __u16 dcid, scid;
-- struct sock *sk;
--
-- scid = __le16_to_cpu(rsp->scid);
-- dcid = __le16_to_cpu(rsp->dcid);
--
-- DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
-- l2cap_sock_clear_timer(sk);
-- l2cap_chan_del(sk, ECONNABORTED);
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
--
-- return 0;
--}
--
--static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
--{
-- __u8 *data = skb->data;
-- int len = skb->len;
-- l2cap_cmd_hdr cmd;
-- int err = 0;
--
-- while (len >= L2CAP_CMD_HDR_SIZE) {
-- memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-- data += L2CAP_CMD_HDR_SIZE;
-- len -= L2CAP_CMD_HDR_SIZE;
--
-- cmd.len = __le16_to_cpu(cmd.len);
--
-- DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
--
-- if (cmd.len > len || !cmd.ident) {
-- DBG("corrupted command");
-- break;
-- }
--
-- switch (cmd.code) {
-- case L2CAP_CONN_REQ:
-- err = l2cap_connect_req(conn, &cmd, data);
-- break;
--
-- case L2CAP_CONN_RSP:
-- err = l2cap_connect_rsp(conn, &cmd, data);
-- break;
--
-- case L2CAP_CONF_REQ:
-- err = l2cap_config_req(conn, &cmd, data);
-- break;
--
-- case L2CAP_CONF_RSP:
-- err = l2cap_config_rsp(conn, &cmd, data);
-- break;
--
-- case L2CAP_DISCONN_REQ:
-- err = l2cap_disconnect_req(conn, &cmd, data);
-- break;
--
-- case L2CAP_DISCONN_RSP:
-- err = l2cap_disconnect_rsp(conn, &cmd, data);
-- break;
--
-- case L2CAP_COMMAND_REJ:
-- /* FIXME: We should process this */
-- l2cap_raw_recv(conn, skb);
-- break;
--
-- case L2CAP_ECHO_REQ:
-- l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
-- break;
--
-- case L2CAP_ECHO_RSP:
-- case L2CAP_INFO_REQ:
-- case L2CAP_INFO_RSP:
-- l2cap_raw_recv(conn, skb);
-- break;
--
-- default:
-- ERR("Uknown signaling command 0x%2.2x", cmd.code);
-- err = -EINVAL;
-- break;
-- };
--
-- if (err) {
-- l2cap_cmd_rej rej;
-- DBG("error %d", err);
--
-- /* FIXME: Map err to a valid reason. */
-- rej.reason = __cpu_to_le16(0);
-- l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
-- }
--
-- data += cmd.len;
-- len -= cmd.len;
-- }
--
-- kfree_skb(skb);
--}
--
--static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
--{
-- struct sock *sk;
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
-- DBG("unknown cid 0x%4.4x", cid);
-- goto drop;
-- }
--
-- DBG("sk %p, len %d", sk, skb->len);
--
-- if (sk->state != BT_CONNECTED)
-- goto drop;
--
-- if (l2cap_pi(sk)->imtu < skb->len)
-- goto drop;
--
-- skb_queue_tail(&sk->receive_queue, skb);
-- sk->data_ready(sk, skb->len);
--
-- return 0;
--
--drop:
-- kfree_skb(skb);
--
-- return 0;
--}
--
--static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
--{
-- l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-- __u16 cid, len;
--
-- skb_pull(skb, L2CAP_HDR_SIZE);
-- cid = __le16_to_cpu(lh->cid);
-- len = __le16_to_cpu(lh->len);
--
-- DBG("len %d, cid 0x%4.4x", len, cid);
--
-- if (cid == 0x0001)
-- l2cap_sig_channel(conn, skb);
-- else
-- l2cap_data_channel(conn, cid, skb);
--}
--
--/* ------------ L2CAP interface with lower layer (HCI) ------------- */
--static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
--{
-- struct hci_dev *hdev = (struct hci_dev *) ptr;
--
-- DBG("hdev %s, event %ld", hdev->name, event);
--
-- write_lock(&l2cap_rt_lock);
--
-- switch (event) {
-- case HCI_DEV_UP:
-- l2cap_iff_add(hdev);
-- break;
--
-- case HCI_DEV_DOWN:
-- l2cap_iff_del(hdev);
-- break;
-- };
--
-- write_unlock(&l2cap_rt_lock);
--
-- return NOTIFY_DONE;
--}
--
--int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
--{
-- struct l2cap_iff *iff;
--
-- DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
--
-- if (!(iff = hdev->l2cap_data)) {
-- ERR("unknown interface");
-- return 0;
-- }
--
-- /* Always accept connection */
-- return 1;
--}
--
--int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
--{
-- struct l2cap_conn *conn;
-- struct l2cap_iff *iff;
-- int err = 0;
--
-- DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
--
-- if (!(iff = hdev->l2cap_data)) {
-- ERR("unknown interface");
-- return 0;
-- }
--
-- l2cap_iff_lock(iff);
--
-- conn = l2cap_get_conn_by_addr(iff, bdaddr);
--
-- if (conn) {
-- /* Outgoing connection */
-- DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
--
-- if (!status && hconn) {
-- conn->state = BT_CONNECTED;
-- conn->hconn = hconn;
--
-- hconn->l2cap_data = (void *)conn;
--
-- /* Establish channels */
-- l2cap_conn_ready(conn);
-- } else {
-- l2cap_conn_del(conn, bterr(status));
-- }
-- } else {
-- /* Incomming connection */
-- DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
--
-- if (status || !hconn)
-- goto done;
--
-- if (!(conn = l2cap_conn_add(iff, bdaddr))) {
-- err = -ENOMEM;
-- goto done;
-- }
--
-- conn->hconn = hconn;
-- hconn->l2cap_data = (void *)conn;
--
-- conn->state = BT_CONNECTED;
-- }
--
--done:
-- l2cap_iff_unlock(iff);
--
-- return err;
--}
--
--int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
--{
-- struct l2cap_conn *conn = hconn->l2cap_data;
--
-- DBG("hconn %p reason %d", hconn, reason);
--
-- if (!conn) {
-- ERR("unknown connection");
-- return 0;
-- }
-- conn->hconn = NULL;
--
-- l2cap_iff_lock(conn->iff);
-- l2cap_conn_del(conn, bterr(reason));
-- l2cap_iff_unlock(conn->iff);
--
-- return 0;
--}
--
--int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
--{
-- struct l2cap_conn *conn = hconn->l2cap_data;
--
-- if (!conn) {
-- ERR("unknown connection %p", hconn);
-- goto drop;
-- }
--
-- DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
--
-- if (flags & ACL_START) {
-- int flen, tlen, size;
-- l2cap_hdr *lh;
--
-- if (conn->rx_len) {
-- ERR("Unexpected start frame (len %d)", skb->len);
-- kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
-- conn->rx_len = 0;
-- }
--
-- if (skb->len < L2CAP_HDR_SIZE) {
-- ERR("Frame is too small (len %d)", skb->len);
-- goto drop;
-- }
--
-- lh = (l2cap_hdr *)skb->data;
-- tlen = __le16_to_cpu(lh->len);
-- flen = skb->len - L2CAP_HDR_SIZE;
--
-- DBG("Start: total len %d, frag len %d", tlen, flen);
--
-- if (flen == tlen) {
-- /* Complete frame received */
-- l2cap_recv_frame(conn, skb);
-- return 0;
-- }
--
-- /* Allocate skb for the complete frame (with header) */
-- size = L2CAP_HDR_SIZE + tlen;
-- if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
-- goto drop;
--
-- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
--
-- conn->rx_len = tlen - flen;
-- } else {
-- DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
--
-- if (!conn->rx_len) {
-- ERR("Unexpected continuation frame (len %d)", skb->len);
-- goto drop;
-- }
--
-- if (skb->len > conn->rx_len) {
-- ERR("Fragment is too large (len %d)", skb->len);
-- kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
-- goto drop;
-- }
--
-- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-- conn->rx_len -= skb->len;
--
-- if (!conn->rx_len) {
-- /* Complete frame received */
-- l2cap_recv_frame(conn, conn->rx_skb);
-- conn->rx_skb = NULL;
-- }
-- }
--
--drop:
-- kfree_skb(skb);
-- return 0;
--}
--
--struct proto_ops l2cap_sock_ops = {
-- family: PF_BLUETOOTH,
-- release: l2cap_sock_release,
-- bind: l2cap_sock_bind,
-- connect: l2cap_sock_connect,
-- listen: l2cap_sock_listen,
-- accept: l2cap_sock_accept,
-- getname: l2cap_sock_getname,
-- sendmsg: l2cap_sock_sendmsg,
-- recvmsg: l2cap_sock_recvmsg,
-- poll: l2cap_sock_poll,
-- socketpair: sock_no_socketpair,
-- ioctl: sock_no_ioctl,
-- shutdown: sock_no_shutdown,
-- setsockopt: l2cap_sock_setsockopt,
-- getsockopt: l2cap_sock_getsockopt,
-- mmap: sock_no_mmap
--};
--
--struct net_proto_family l2cap_sock_family_ops = {
-- family: PF_BLUETOOTH,
-- create: l2cap_sock_create
--};
--
--struct hci_proto l2cap_hci_proto = {
-- name: "L2CAP",
-- id: HCI_PROTO_L2CAP,
-- connect_ind: l2cap_connect_ind,
-- connect_cfm: l2cap_connect_cfm,
-- disconn_ind: l2cap_disconn_ind,
-- recv_acldata: l2cap_recv_acldata,
--};
--
--struct notifier_block l2cap_nblock = {
-- notifier_call: l2cap_dev_event
--};
--
--int __init l2cap_init(void)
--{
-- INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
--
-- if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
-- ERR("Can't register L2CAP socket");
-- return -EPROTO;
-- }
--
-- if (hci_register_proto(&l2cap_hci_proto) < 0) {
-- ERR("Can't register L2CAP protocol");
-- return -EPROTO;
-- }
--
-- hci_register_notifier(&l2cap_nblock);
--
-- l2cap_register_proc();
--
-- return 0;
--}
--
--void l2cap_cleanup(void)
--{
-- l2cap_unregister_proc();
--
-- /* Unregister socket, protocol and notifier */
-- if (bluez_sock_unregister(BTPROTO_L2CAP))
-- ERR("Can't unregister L2CAP socket");
--
-- if (hci_unregister_proto(&l2cap_hci_proto) < 0)
-- ERR("Can't unregister L2CAP protocol");
--
-- hci_unregister_notifier(&l2cap_nblock);
--
-- /* We _must_ not have any sockets and/or connections
-- * at this stage.
-- */
--
-- /* Free interface list and unlock HCI devices */
-- {
-- struct list_head *list = &l2cap_iff_list;
--
-- while (!list_empty(list)) {
-- struct l2cap_iff *iff;
--
-- iff = list_entry(list->next, struct l2cap_iff, list);
-- l2cap_iff_del(iff->hdev);
-- }
-- }
--}
--
--module_init(l2cap_init);
--module_exit(l2cap_cleanup);
--
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
--MODULE_LICENSE("GPL");
--
-diff -urN linux-2.4.18/net/bluetooth/l2cap_proc.c linux-2.4.18-mh15/net/bluetooth/l2cap_proc.c
---- linux-2.4.18/net/bluetooth/l2cap_proc.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/l2cap_proc.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,165 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * BlueZ L2CAP proc fs support.
-- *
-- * $Id$
-- */
--
--#include <linux/config.h>
--#include <linux/module.h>
--
--#include <linux/types.h>
--#include <linux/errno.h>
--#include <linux/kernel.h>
--#include <linux/major.h>
--#include <linux/sched.h>
--#include <linux/slab.h>
--#include <linux/poll.h>
--#include <linux/fcntl.h>
--#include <linux/init.h>
--#include <linux/skbuff.h>
--#include <linux/interrupt.h>
--#include <linux/socket.h>
--#include <linux/skbuff.h>
--#include <linux/proc_fs.h>
--#include <linux/list.h>
--#include <net/sock.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/l2cap_core.h>
--
--#ifndef L2CAP_DEBUG
--#undef DBG
--#define DBG( A... )
--#endif
--
--/* ----- PROC fs support ----- */
--static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
--{
-- struct list_head *p;
-- char *ptr = buf;
--
-- list_for_each(p, &iff->conn_list) {
-- struct l2cap_conn *c;
--
-- c = list_entry(p, struct l2cap_conn, list);
-- ptr += sprintf(ptr, " %p %d %p %p %s %s\n",
-- c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
-- }
--
-- return ptr - buf;
--}
--
--static int l2cap_iff_dump(char *buf)
--{
-- struct list_head *p;
-- char *ptr = buf;
--
-- ptr += sprintf(ptr, "Interfaces:\n");
--
-- write_lock(&l2cap_rt_lock);
--
-- list_for_each(p, &l2cap_iff_list) {
-- struct l2cap_iff *iff;
--
-- iff = list_entry(p, struct l2cap_iff, list);
--
-- ptr += sprintf(ptr, " %s %p %p\n", iff->hdev->name, iff, iff->hdev);
--
-- l2cap_iff_lock(iff);
-- ptr += l2cap_conn_dump(ptr, iff);
-- l2cap_iff_unlock(iff);
-- }
--
-- write_unlock(&l2cap_rt_lock);
--
-- ptr += sprintf(ptr, "\n");
--
-- return ptr - buf;
--}
--
--static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
--{
-- struct l2cap_pinfo *pi;
-- struct sock *sk;
-- char *ptr = buf;
--
-- ptr += sprintf(ptr, "Sockets:\n");
--
-- write_lock(&list->lock);
--
-- for (sk = list->head; sk; sk = sk->next) {
-- pi = l2cap_pi(sk);
-- ptr += sprintf(ptr, " %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
-- batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
-- }
--
-- write_unlock(&list->lock);
--
-- ptr += sprintf(ptr, "\n");
--
-- return ptr - buf;
--}
--
--static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
--{
-- char *ptr = buf;
-- int len;
--
-- DBG("count %d, offset %ld", count, offset);
--
-- ptr += l2cap_iff_dump(ptr);
-- ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
-- len = ptr - buf;
--
-- if (len <= count + offset)
-- *eof = 1;
--
-- *start = buf + offset;
-- len -= offset;
--
-- if (len > count)
-- len = count;
-- if (len < 0)
-- len = 0;
--
-- return len;
--}
--
--void l2cap_register_proc(void)
--{
-- create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
--}
--
--void l2cap_unregister_proc(void)
--{
-- remove_proc_entry("bluetooth/l2cap", NULL);
--}
-diff -urN linux-2.4.18/net/bluetooth/lib.c linux-2.4.18-mh15/net/bluetooth/lib.c
---- linux-2.4.18/net/bluetooth/lib.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/lib.c 2004-08-01 16:26:23.000000000 +0200
-@@ -25,7 +25,7 @@
- /*
- * BlueZ kernel library.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/kernel.h>
-@@ -105,7 +105,7 @@
- return EACCES;
-
- case 0x06:
-- return EINVAL;
-+ return EBADE;
-
- case 0x07:
- return ENOMEM;
-diff -urN linux-2.4.18/net/bluetooth/Makefile linux-2.4.18-mh15/net/bluetooth/Makefile
---- linux-2.4.18/net/bluetooth/Makefile 2001-06-12 04:15:27.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -1,20 +1,40 @@
- #
--# Makefile for the Bluetooth subsystem
-+# Makefile for the Linux Bluetooth subsystem
- #
--O_TARGET := bluetooth.o
-
--list-multi := hci.o l2cap.o
--export-objs := syms.o
--hci-objs := af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
--l2cap-objs := l2cap_core.o l2cap_proc.o
-+O_TARGET := bluetooth.o
-
--obj-$(CONFIG_BLUEZ) += hci.o
-+list-multi := bluez.o
-+export-objs := syms.o l2cap.o
-+
-+bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
-+
-+obj-$(CONFIG_BLUEZ) += bluez.o
- obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
-+obj-$(CONFIG_BLUEZ_SCO) += sco.o
-
--include $(TOPDIR)/Rules.make
-+subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
-+subdir-$(CONFIG_BLUEZ_BNEP) += bnep
-+subdir-$(CONFIG_BLUEZ_CMTP) += cmtp
-+subdir-$(CONFIG_BLUEZ_HIDP) += hidp
-+
-+ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
-+obj-y += rfcomm/rfcomm.o
-+endif
-
--hci.o: $(hci-objs)
-- $(LD) -r -o $@ $(hci-objs)
-+ifeq ($(CONFIG_BLUEZ_BNEP),y)
-+obj-y += bnep/bnep.o
-+endif
-+
-+ifeq ($(CONFIG_BLUEZ_CMTP),y)
-+obj-y += cmtp/cmtp.o
-+endif
-+
-+ifeq ($(CONFIG_BLUEZ_HIDP),y)
-+obj-y += hidp/hidp.o
-+endif
-+
-+include $(TOPDIR)/Rules.make
-
--l2cap.o: $(l2cap-objs)
-- $(LD) -r -o $@ $(l2cap-objs)
-+bluez.o: $(bluez-objs)
-+ $(LD) -r -o $@ $(bluez-objs)
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/Config.in linux-2.4.18-mh15/net/bluetooth/rfcomm/Config.in
---- linux-2.4.18/net/bluetooth/rfcomm/Config.in 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/rfcomm/Config.in 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,10 @@
-+#
-+# Bluetooth RFCOMM layer configuration
-+#
-+
-+dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
-+
-+if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
-+ bool ' RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
-+fi
-+
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/core.c linux-2.4.18-mh15/net/bluetooth/rfcomm/core.c
---- linux-2.4.18/net/bluetooth/rfcomm/core.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/rfcomm/core.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,1940 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ RPN support - Dirk Husemann <hud@zurich.ibm.com>
-+*/
-+
-+/*
-+ * RFCOMM core.
-+ *
-+ * $Id$
-+ */
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/init.h>
-+#include <linux/wait.h>
-+#include <linux/net.h>
-+#include <linux/proc_fs.h>
-+#include <net/sock.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#define VERSION "1.1"
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+struct task_struct *rfcomm_thread;
-+DECLARE_MUTEX(rfcomm_sem);
-+unsigned long rfcomm_event;
-+
-+static LIST_HEAD(session_list);
-+static atomic_t terminate, running;
-+
-+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
-+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
-+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
-+static int rfcomm_queue_disc(struct rfcomm_dlc *d);
-+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
-+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
-+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
-+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
-+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
-+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
-+
-+static void rfcomm_process_connect(struct rfcomm_session *s);
-+
-+/* ---- RFCOMM frame parsing macros ---- */
-+#define __get_dlci(b) ((b & 0xfc) >> 2)
-+#define __get_channel(b) ((b & 0xf8) >> 3)
-+#define __get_dir(b) ((b & 0x04) >> 2)
-+#define __get_type(b) ((b & 0xef))
-+
-+#define __test_ea(b) ((b & 0x01))
-+#define __test_cr(b) ((b & 0x02))
-+#define __test_pf(b) ((b & 0x10))
-+
-+#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
-+#define __ctrl(type, pf) (((type & 0xef) | (pf << 4)))
-+#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir)
-+#define __srv_channel(dlci) (dlci >> 1)
-+#define __dir(dlci) (dlci & 0x01)
-+
-+#define __len8(len) (((len) << 1) | 1)
-+#define __len16(len) ((len) << 1)
-+
-+/* MCC macros */
-+#define __mcc_type(cr, type) (((type << 2) | (cr << 1) | 0x01))
-+#define __get_mcc_type(b) ((b & 0xfc) >> 2)
-+#define __get_mcc_len(b) ((b & 0xfe) >> 1)
-+
-+/* RPN macros */
-+#define __rpn_line_settings(data, stop, parity) ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
-+#define __get_rpn_data_bits(line) ((line) & 0x3)
-+#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
-+#define __get_rpn_parity(line) (((line) >> 3) & 0x3)
-+
-+/* ---- RFCOMM FCS computation ---- */
-+
-+/* CRC on 2 bytes */
-+#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
-+
-+/* FCS on 2 bytes */
-+static inline u8 __fcs(u8 *data)
-+{
-+ return (0xff - __crc(data));
-+}
-+
-+/* FCS on 3 bytes */
-+static inline u8 __fcs2(u8 *data)
-+{
-+ return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
-+}
-+
-+/* Check FCS */
-+static inline int __check_fcs(u8 *data, int type, u8 fcs)
-+{
-+ u8 f = __crc(data);
-+
-+ if (type != RFCOMM_UIH)
-+ f = rfcomm_crc_table[f ^ data[2]];
-+
-+ return rfcomm_crc_table[f ^ fcs] != 0xcf;
-+}
-+
-+/* ---- L2CAP callbacks ---- */
-+static void rfcomm_l2state_change(struct sock *sk)
-+{
-+ BT_DBG("%p state %d", sk, sk->state);
-+ rfcomm_schedule(RFCOMM_SCHED_STATE);
-+}
-+
-+static void rfcomm_l2data_ready(struct sock *sk, int bytes)
-+{
-+ BT_DBG("%p bytes %d", sk, bytes);
-+ rfcomm_schedule(RFCOMM_SCHED_RX);
-+}
-+
-+static int rfcomm_l2sock_create(struct socket **sock)
-+{
-+ int err;
-+
-+ BT_DBG("");
-+
-+ err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
-+ if (!err) {
-+ struct sock *sk = (*sock)->sk;
-+ sk->data_ready = rfcomm_l2data_ready;
-+ sk->state_change = rfcomm_l2state_change;
-+ }
-+ return err;
-+}
-+
-+/* ---- RFCOMM DLCs ---- */
-+static void rfcomm_dlc_timeout(unsigned long arg)
-+{
-+ struct rfcomm_dlc *d = (void *) arg;
-+
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ set_bit(RFCOMM_TIMED_OUT, &d->flags);
-+ rfcomm_dlc_put(d);
-+ rfcomm_schedule(RFCOMM_SCHED_TIMEO);
-+}
-+
-+static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
-+{
-+ BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
-+
-+ if (!mod_timer(&d->timer, jiffies + timeout))
-+ rfcomm_dlc_hold(d);
-+}
-+
-+static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ if (timer_pending(&d->timer) && del_timer(&d->timer))
-+ rfcomm_dlc_put(d);
-+}
-+
-+static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("%p", d);
-+
-+ d->state = BT_OPEN;
-+ d->flags = 0;
-+ d->mscex = 0;
-+ d->mtu = RFCOMM_DEFAULT_MTU;
-+ d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
-+
-+ d->cfc = RFCOMM_CFC_DISABLED;
-+ d->rx_credits = RFCOMM_DEFAULT_CREDITS;
-+}
-+
-+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
-+{
-+ struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
-+ if (!d)
-+ return NULL;
-+ memset(d, 0, sizeof(*d));
-+
-+ init_timer(&d->timer);
-+ d->timer.function = rfcomm_dlc_timeout;
-+ d->timer.data = (unsigned long) d;
-+
-+ skb_queue_head_init(&d->tx_queue);
-+ spin_lock_init(&d->lock);
-+ atomic_set(&d->refcnt, 1);
-+
-+ rfcomm_dlc_clear_state(d);
-+
-+ BT_DBG("%p", d);
-+ return d;
-+}
-+
-+void rfcomm_dlc_free(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("%p", d);
-+
-+ skb_queue_purge(&d->tx_queue);
-+ kfree(d);
-+}
-+
-+static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p session %p", d, s);
-+
-+ rfcomm_session_hold(s);
-+
-+ rfcomm_dlc_hold(d);
-+ list_add(&d->list, &s->dlcs);
-+ d->session = s;
-+}
-+
-+static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
-+{
-+ struct rfcomm_session *s = d->session;
-+
-+ BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
-+
-+ list_del(&d->list);
-+ d->session = NULL;
-+ rfcomm_dlc_put(d);
-+
-+ rfcomm_session_put(s);
-+}
-+
-+static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p;
-+
-+ list_for_each(p, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ if (d->dlci == dlci)
-+ return d;
-+ }
-+ return NULL;
-+}
-+
-+static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-+{
-+ struct rfcomm_session *s;
-+ int err = 0;
-+ u8 dlci;
-+
-+ BT_DBG("dlc %p state %ld %s %s channel %d",
-+ d, d->state, batostr(src), batostr(dst), channel);
-+
-+ if (channel < 1 || channel > 30)
-+ return -EINVAL;
-+
-+ if (d->state != BT_OPEN && d->state != BT_CLOSED)
-+ return 0;
-+
-+ s = rfcomm_session_get(src, dst);
-+ if (!s) {
-+ s = rfcomm_session_create(src, dst, &err);
-+ if (!s)
-+ return err;
-+ }
-+
-+ dlci = __dlci(!s->initiator, channel);
-+
-+ /* Check if DLCI already exists */
-+ if (rfcomm_dlc_get(s, dlci))
-+ return -EBUSY;
-+
-+ rfcomm_dlc_clear_state(d);
-+
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ d->priority = 7;
-+
-+ d->state = BT_CONFIG;
-+ rfcomm_dlc_link(s, d);
-+
-+ d->mtu = s->mtu;
-+ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
-+
-+ if (s->state == BT_CONNECTED)
-+ rfcomm_send_pn(s, 1, d);
-+ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-+ return 0;
-+}
-+
-+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-+{
-+ mm_segment_t fs;
-+ int r;
-+
-+ rfcomm_lock();
-+
-+ fs = get_fs(); set_fs(KERNEL_DS);
-+ r = __rfcomm_dlc_open(d, src, dst, channel);
-+ set_fs(fs);
-+
-+ rfcomm_unlock();
-+ return r;
-+}
-+
-+static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-+{
-+ struct rfcomm_session *s = d->session;
-+ if (!s)
-+ return 0;
-+
-+ BT_DBG("dlc %p state %ld dlci %d err %d session %p",
-+ d, d->state, d->dlci, err, s);
-+
-+ switch (d->state) {
-+ case BT_CONNECTED:
-+ case BT_CONFIG:
-+ case BT_CONNECT:
-+ d->state = BT_DISCONN;
-+ if (skb_queue_empty(&d->tx_queue)) {
-+ rfcomm_send_disc(s, d->dlci);
-+ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
-+ } else {
-+ rfcomm_queue_disc(d);
-+ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
-+ }
-+ break;
-+
-+ default:
-+ rfcomm_dlc_clear_timer(d);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CLOSED;
-+ d->state_change(d, err);
-+ rfcomm_dlc_unlock(d);
-+
-+ skb_queue_purge(&d->tx_queue);
-+ rfcomm_dlc_unlink(d);
-+ }
-+
-+ return 0;
-+}
-+
-+int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-+{
-+ mm_segment_t fs;
-+ int r;
-+
-+ rfcomm_lock();
-+
-+ fs = get_fs(); set_fs(KERNEL_DS);
-+ r = __rfcomm_dlc_close(d, err);
-+ set_fs(fs);
-+
-+ rfcomm_unlock();
-+ return r;
-+}
-+
-+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
-+{
-+ int len = skb->len;
-+
-+ if (d->state != BT_CONNECTED)
-+ return -ENOTCONN;
-+
-+ BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
-+
-+ if (len > d->mtu)
-+ return -EINVAL;
-+
-+ rfcomm_make_uih(skb, d->addr);
-+ skb_queue_tail(&d->tx_queue, skb);
-+
-+ if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+ return len;
-+}
-+
-+void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ if (!d->cfc) {
-+ d->v24_sig |= RFCOMM_V24_FC;
-+ set_bit(RFCOMM_MSC_PENDING, &d->flags);
-+ }
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+}
-+
-+void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ if (!d->cfc) {
-+ d->v24_sig &= ~RFCOMM_V24_FC;
-+ set_bit(RFCOMM_MSC_PENDING, &d->flags);
-+ }
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+}
-+
-+/*
-+ Set/get modem status functions use _local_ status i.e. what we report
-+ to the other side.
-+ Remote status is provided by dlc->modem_status() callback.
-+ */
-+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
-+{
-+ BT_DBG("dlc %p state %ld v24_sig 0x%x",
-+ d, d->state, v24_sig);
-+
-+ if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+ v24_sig |= RFCOMM_V24_FC;
-+ else
-+ v24_sig &= ~RFCOMM_V24_FC;
-+
-+ d->v24_sig = v24_sig;
-+
-+ if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+
-+ return 0;
-+}
-+
-+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
-+{
-+ BT_DBG("dlc %p state %ld v24_sig 0x%x",
-+ d, d->state, d->v24_sig);
-+
-+ *v24_sig = d->v24_sig;
-+ return 0;
-+}
-+
-+/* ---- RFCOMM sessions ---- */
-+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
-+{
-+ struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
-+ if (!s)
-+ return NULL;
-+ memset(s, 0, sizeof(*s));
-+
-+ BT_DBG("session %p sock %p", s, sock);
-+
-+ INIT_LIST_HEAD(&s->dlcs);
-+ s->state = state;
-+ s->sock = sock;
-+
-+ s->mtu = RFCOMM_DEFAULT_MTU;
-+ s->cfc = RFCOMM_CFC_UNKNOWN;
-+
-+ list_add(&s->list, &session_list);
-+
-+ /* Do not increment module usage count for listeting sessions.
-+ * Otherwise we won't be able to unload the module. */
-+ if (state != BT_LISTEN)
-+ MOD_INC_USE_COUNT;
-+ return s;
-+}
-+
-+void rfcomm_session_del(struct rfcomm_session *s)
-+{
-+ int state = s->state;
-+
-+ BT_DBG("session %p state %ld", s, s->state);
-+
-+ list_del(&s->list);
-+
-+ if (state == BT_CONNECTED)
-+ rfcomm_send_disc(s, 0);
-+
-+ sock_release(s->sock);
-+ kfree(s);
-+
-+ if (state != BT_LISTEN)
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
-+{
-+ struct rfcomm_session *s;
-+ struct list_head *p, *n;
-+ struct bluez_pinfo *pi;
-+ list_for_each_safe(p, n, &session_list) {
-+ s = list_entry(p, struct rfcomm_session, list);
-+ pi = bluez_pi(s->sock->sk);
-+
-+ if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
-+ !bacmp(&pi->dst, dst))
-+ return s;
-+ }
-+ return NULL;
-+}
-+
-+void rfcomm_session_close(struct rfcomm_session *s, int err)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("session %p state %ld err %d", s, s->state, err);
-+
-+ rfcomm_session_hold(s);
-+
-+ s->state = BT_CLOSED;
-+
-+ /* Close all dlcs */
-+ list_for_each_safe(p, n, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, err);
-+ }
-+
-+ rfcomm_session_put(s);
-+}
-+
-+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
-+{
-+ struct rfcomm_session *s = NULL;
-+ struct sockaddr_l2 addr;
-+ struct l2cap_options opts;
-+ struct socket *sock;
-+ int size;
-+
-+ BT_DBG("%s %s", batostr(src), batostr(dst));
-+
-+ *err = rfcomm_l2sock_create(&sock);
-+ if (*err < 0)
-+ return NULL;
-+
-+ bacpy(&addr.l2_bdaddr, src);
-+ addr.l2_family = AF_BLUETOOTH;
-+ addr.l2_psm = 0;
-+ *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-+ if (*err < 0)
-+ goto failed;
-+
-+ /* Set L2CAP options */
-+ size = sizeof(opts);
-+ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
-+
-+ opts.imtu = RFCOMM_MAX_L2CAP_MTU;
-+ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
-+
-+ s = rfcomm_session_add(sock, BT_BOUND);
-+ if (!s) {
-+ *err = -ENOMEM;
-+ goto failed;
-+ }
-+
-+ s->initiator = 1;
-+
-+ bacpy(&addr.l2_bdaddr, dst);
-+ addr.l2_family = AF_BLUETOOTH;
-+ addr.l2_psm = htobs(RFCOMM_PSM);
-+ *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
-+ if (*err == 0 || *err == -EAGAIN)
-+ return s;
-+
-+ rfcomm_session_del(s);
-+ return NULL;
-+
-+failed:
-+ sock_release(sock);
-+ return NULL;
-+}
-+
-+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
-+{
-+ struct sock *sk = s->sock->sk;
-+ if (src)
-+ bacpy(src, &bluez_pi(sk)->src);
-+ if (dst)
-+ bacpy(dst, &bluez_pi(sk)->dst);
-+}
-+
-+/* ---- RFCOMM frame sending ---- */
-+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
-+{
-+ struct socket *sock = s->sock;
-+ struct iovec iv = { data, len };
-+ struct msghdr msg;
-+ int err;
-+
-+ BT_DBG("session %p len %d", s, len);
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ err = sock->ops->sendmsg(sock, &msg, len, 0);
-+ return err;
-+}
-+
-+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(!s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_UA, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_queue_disc(struct rfcomm_dlc *d)
-+{
-+ struct rfcomm_cmd *cmd;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("dlc %p dlci %d", d, d->dlci);
-+
-+ skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
-+ if (!skb)
-+ return -ENOMEM;
-+
-+ cmd = (void *) __skb_put(skb, sizeof(*cmd));
-+ cmd->addr = d->addr;
-+ cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
-+ cmd->len = __len8(0);
-+ cmd->fcs = __fcs2((u8 *) cmd);
-+
-+ skb_queue_tail(&d->tx_queue, skb);
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+ return 0;
-+}
-+
-+static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(!s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_DM, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d type %d", s, cr, type);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + 1);
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_NSC);
-+ mcc->len = __len8(1);
-+
-+ /* Type that we didn't like */
-+ *ptr = __mcc_type(cr, type); ptr++;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_pn *pn;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*pn));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_PN);
-+ mcc->len = __len8(sizeof(*pn));
-+
-+ pn = (void *) ptr; ptr += sizeof(*pn);
-+ pn->dlci = d->dlci;
-+ pn->priority = d->priority;
-+ pn->ack_timer = 0;
-+ pn->max_retrans = 0;
-+
-+ if (s->cfc) {
-+ pn->flow_ctrl = cr ? 0xf0 : 0xe0;
-+ pn->credits = RFCOMM_DEFAULT_CREDITS;
-+ } else {
-+ pn->flow_ctrl = 0;
-+ pn->credits = 0;
-+ }
-+
-+ pn->mtu = htobs(d->mtu);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
-+ u8 bit_rate, u8 data_bits, u8 stop_bits,
-+ u8 parity, u8 flow_ctrl_settings,
-+ u8 xon_char, u8 xoff_char, u16 param_mask)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_rpn *rpn;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
-+ "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x",
-+ s, cr, dlci, bit_rate, data_bits, stop_bits, parity,
-+ flow_ctrl_settings, xon_char, xoff_char, param_mask);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*rpn));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_RPN);
-+ mcc->len = __len8(sizeof(*rpn));
-+
-+ rpn = (void *) ptr; ptr += sizeof(*rpn);
-+ rpn->dlci = __addr(1, dlci);
-+ rpn->bit_rate = bit_rate;
-+ rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
-+ rpn->flow_ctrl = flow_ctrl_settings;
-+ rpn->xon_char = xon_char;
-+ rpn->xoff_char = xoff_char;
-+ rpn->param_mask = param_mask;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_rls *rls;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d status 0x%x", s, cr, status);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*rls));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_RLS);
-+ mcc->len = __len8(sizeof(*rls));
-+
-+ rls = (void *) ptr; ptr += sizeof(*rls);
-+ rls->dlci = __addr(1, dlci);
-+ rls->status = status;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_msc *msc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*msc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_MSC);
-+ mcc->len = __len8(sizeof(*msc));
-+
-+ msc = (void *) ptr; ptr += sizeof(*msc);
-+ msc->dlci = __addr(1, dlci);
-+ msc->v24_sig = v24_sig | 0x01;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
-+ mcc->len = __len8(0);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_FCON);
-+ mcc->len = __len8(0);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
-+{
-+ struct socket *sock = s->sock;
-+ struct iovec iv[3];
-+ struct msghdr msg;
-+ unsigned char hdr[5], crc[1];
-+
-+ if (len > 125)
-+ return -EINVAL;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr[0] = __addr(s->initiator, 0);
-+ hdr[1] = __ctrl(RFCOMM_UIH, 0);
-+ hdr[2] = 0x01 | ((len + 2) << 1);
-+ hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
-+ hdr[4] = 0x01 | (len << 1);
-+
-+ crc[0] = __fcs(hdr);
-+
-+ iv[0].iov_base = hdr;
-+ iv[0].iov_len = 5;
-+ iv[1].iov_base = pattern;
-+ iv[1].iov_len = len;
-+ iv[2].iov_base = crc;
-+ iv[2].iov_len = 1;
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 3;
-+ msg.msg_iov = iv;
-+ return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
-+}
-+
-+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
-+{
-+ struct rfcomm_hdr *hdr;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p addr %d credits %d", s, addr, credits);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = addr;
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
-+ hdr->len = __len8(0);
-+
-+ *ptr = credits; ptr++;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ int len = skb->len;
-+ u8 *crc;
-+
-+ if (len > 127) {
-+ hdr = (void *) skb_push(skb, 4);
-+ put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
-+ } else {
-+ hdr = (void *) skb_push(skb, 3);
-+ hdr->len = __len8(len);
-+ }
-+ hdr->addr = addr;
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+
-+ crc = skb_put(skb, 1);
-+ *crc = __fcs((void *) hdr);
-+}
-+
-+/* ---- RFCOMM frame reception ---- */
-+static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
-+{
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (dlci) {
-+ /* Data channel */
-+ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+ if (!d) {
-+ rfcomm_send_dm(s, dlci);
-+ return 0;
-+ }
-+
-+ switch (d->state) {
-+ case BT_CONNECT:
-+ rfcomm_dlc_clear_timer(d);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CONNECTED;
-+ d->state_change(d, 0);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+ break;
-+
-+ case BT_DISCONN:
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, 0);
-+ break;
-+ }
-+ } else {
-+ /* Control channel */
-+ switch (s->state) {
-+ case BT_CONNECT:
-+ s->state = BT_CONNECTED;
-+ rfcomm_process_connect(s);
-+ break;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
-+{
-+ int err = 0;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (dlci) {
-+ /* Data DLC */
-+ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ if (d->state == BT_CONNECT || d->state == BT_CONFIG)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, err);
-+ }
-+ } else {
-+ if (s->state == BT_CONNECT)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ s->state = BT_CLOSED;
-+ rfcomm_session_close(s, err);
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
-+{
-+ int err = 0;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (dlci) {
-+ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ rfcomm_send_ua(s, dlci);
-+
-+ if (d->state == BT_CONNECT || d->state == BT_CONFIG)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, err);
-+ } else
-+ rfcomm_send_dm(s, dlci);
-+
-+ } else {
-+ rfcomm_send_ua(s, 0);
-+
-+ if (s->state == BT_CONNECT)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ s->state = BT_CLOSED;
-+ rfcomm_session_close(s, err);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_dlc *d;
-+ u8 channel;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (!dlci) {
-+ rfcomm_send_ua(s, 0);
-+
-+ if (s->state == BT_OPEN) {
-+ s->state = BT_CONNECTED;
-+ rfcomm_process_connect(s);
-+ }
-+ return 0;
-+ }
-+
-+ /* Check if DLC exists */
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ if (d->state == BT_OPEN) {
-+ /* DLC was previously opened by PN request */
-+ rfcomm_send_ua(s, dlci);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CONNECTED;
-+ d->state_change(d, 0);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+ }
-+ return 0;
-+ }
-+
-+ /* Notify socket layer about incomming connection */
-+ channel = __srv_channel(dlci);
-+ if (rfcomm_connect_ind(s, channel, &d)) {
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ rfcomm_dlc_link(s, d);
-+
-+ rfcomm_send_ua(s, dlci);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CONNECTED;
-+ d->state_change(d, 0);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+ } else {
-+ rfcomm_send_dm(s, dlci);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
-+{
-+ struct rfcomm_session *s = d->session;
-+
-+ BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
-+ d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
-+
-+ if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
-+ d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
-+ d->tx_credits = pn->credits;
-+ } else {
-+ d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ }
-+
-+ d->priority = pn->priority;
-+
-+ d->mtu = s->mtu = btohs(pn->mtu);
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+ struct rfcomm_pn *pn = (void *) skb->data;
-+ struct rfcomm_dlc *d;
-+ u8 dlci = pn->dlci;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (!dlci)
-+ return 0;
-+
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ if (cr) {
-+ /* PN request */
-+ rfcomm_apply_pn(d, cr, pn);
-+ rfcomm_send_pn(s, 0, d);
-+ } else {
-+ /* PN response */
-+ switch (d->state) {
-+ case BT_CONFIG:
-+ rfcomm_apply_pn(d, cr, pn);
-+
-+ d->state = BT_CONNECT;
-+ rfcomm_send_sabm(s, d->dlci);
-+ break;
-+ }
-+ }
-+ } else {
-+ u8 channel = __srv_channel(dlci);
-+
-+ if (!cr)
-+ return 0;
-+
-+ /* PN request for non existing DLC.
-+ * Assume incomming connection. */
-+ if (rfcomm_connect_ind(s, channel, &d)) {
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ rfcomm_dlc_link(s, d);
-+
-+ rfcomm_apply_pn(d, cr, pn);
-+
-+ d->state = BT_OPEN;
-+ rfcomm_send_pn(s, 0, d);
-+ } else {
-+ rfcomm_send_dm(s, dlci);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
-+{
-+ struct rfcomm_rpn *rpn = (void *) skb->data;
-+ u8 dlci = __get_dlci(rpn->dlci);
-+
-+ u8 bit_rate = 0;
-+ u8 data_bits = 0;
-+ u8 stop_bits = 0;
-+ u8 parity = 0;
-+ u8 flow_ctrl = 0;
-+ u8 xon_char = 0;
-+ u8 xoff_char = 0;
-+ u16 rpn_mask = RFCOMM_RPN_PM_ALL;
-+
-+ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
-+ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
-+ rpn->xon_char, rpn->xoff_char, rpn->param_mask);
-+
-+ if (!cr)
-+ return 0;
-+
-+ if (len == 1) {
-+ /* request: return default setting */
-+ bit_rate = RFCOMM_RPN_BR_115200;
-+ data_bits = RFCOMM_RPN_DATA_8;
-+ stop_bits = RFCOMM_RPN_STOP_1;
-+ parity = RFCOMM_RPN_PARITY_NONE;
-+ flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+ xon_char = RFCOMM_RPN_XON_CHAR;
-+ xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+
-+ goto rpn_out;
-+ }
-+ /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
-+ no flow control lines, normal XON/XOFF chars */
-+ if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
-+ bit_rate = rpn->bit_rate;
-+ if (bit_rate != RFCOMM_RPN_BR_115200) {
-+ BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
-+ bit_rate = RFCOMM_RPN_BR_115200;
-+ rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
-+ data_bits = __get_rpn_data_bits(rpn->line_settings);
-+ if (data_bits != RFCOMM_RPN_DATA_8) {
-+ BT_DBG("RPN data bits mismatch 0x%x", data_bits);
-+ data_bits = RFCOMM_RPN_DATA_8;
-+ rpn_mask ^= RFCOMM_RPN_PM_DATA;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
-+ stop_bits = __get_rpn_stop_bits(rpn->line_settings);
-+ if (stop_bits != RFCOMM_RPN_STOP_1) {
-+ BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
-+ stop_bits = RFCOMM_RPN_STOP_1;
-+ rpn_mask ^= RFCOMM_RPN_PM_STOP;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
-+ parity = __get_rpn_parity(rpn->line_settings);
-+ if (parity != RFCOMM_RPN_PARITY_NONE) {
-+ BT_DBG("RPN parity mismatch 0x%x", parity);
-+ parity = RFCOMM_RPN_PARITY_NONE;
-+ rpn_mask ^= RFCOMM_RPN_PM_PARITY;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
-+ flow_ctrl = rpn->flow_ctrl;
-+ if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
-+ BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
-+ flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+ rpn_mask ^= RFCOMM_RPN_PM_FLOW;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
-+ xon_char = rpn->xon_char;
-+ if (xon_char != RFCOMM_RPN_XON_CHAR) {
-+ BT_DBG("RPN XON char mismatch 0x%x", xon_char);
-+ xon_char = RFCOMM_RPN_XON_CHAR;
-+ rpn_mask ^= RFCOMM_RPN_PM_XON;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
-+ xoff_char = rpn->xoff_char;
-+ if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
-+ BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
-+ xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+ rpn_mask ^= RFCOMM_RPN_PM_XOFF;
-+ }
-+ }
-+
-+rpn_out:
-+ rfcomm_send_rpn(s, 0, dlci,
-+ bit_rate, data_bits, stop_bits, parity, flow_ctrl,
-+ xon_char, xoff_char, rpn_mask);
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+ struct rfcomm_rls *rls = (void *) skb->data;
-+ u8 dlci = __get_dlci(rls->dlci);
-+
-+ BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
-+
-+ if (!cr)
-+ return 0;
-+
-+ /* FIXME: We should probably do something with this
-+ information here. But for now it's sufficient just
-+ to reply -- Bluetooth 1.1 says it's mandatory to
-+ recognise and respond to RLS */
-+
-+ rfcomm_send_rls(s, 0, dlci, rls->status);
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+ struct rfcomm_msc *msc = (void *) skb->data;
-+ struct rfcomm_dlc *d;
-+ u8 dlci = __get_dlci(msc->dlci);
-+
-+ BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
-+
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (!d)
-+ return 0;
-+
-+ if (cr) {
-+ if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ else
-+ clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+
-+ rfcomm_dlc_lock(d);
-+ if (d->modem_status)
-+ d->modem_status(d, msc->v24_sig);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
-+
-+ d->mscex |= RFCOMM_MSCEX_RX;
-+ } else
-+ d->mscex |= RFCOMM_MSCEX_TX;
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
-+{
-+ struct rfcomm_mcc *mcc = (void *) skb->data;
-+ u8 type, cr, len;
-+
-+ cr = __test_cr(mcc->type);
-+ type = __get_mcc_type(mcc->type);
-+ len = __get_mcc_len(mcc->len);
-+
-+ BT_DBG("%p type 0x%x cr %d", s, type, cr);
-+
-+ skb_pull(skb, 2);
-+
-+ switch (type) {
-+ case RFCOMM_PN:
-+ rfcomm_recv_pn(s, cr, skb);
-+ break;
-+
-+ case RFCOMM_RPN:
-+ rfcomm_recv_rpn(s, cr, len, skb);
-+ break;
-+
-+ case RFCOMM_RLS:
-+ rfcomm_recv_rls(s, cr, skb);
-+ break;
-+
-+ case RFCOMM_MSC:
-+ rfcomm_recv_msc(s, cr, skb);
-+ break;
-+
-+ case RFCOMM_FCOFF:
-+ if (cr) {
-+ set_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+ rfcomm_send_fcoff(s, 0);
-+ }
-+ break;
-+
-+ case RFCOMM_FCON:
-+ if (cr) {
-+ clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+ rfcomm_send_fcon(s, 0);
-+ }
-+ break;
-+
-+ case RFCOMM_TEST:
-+ if (cr)
-+ rfcomm_send_test(s, 0, skb->data, skb->len);
-+ break;
-+
-+ case RFCOMM_NSC:
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown control type 0x%02x", type);
-+ rfcomm_send_nsc(s, cr, type);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
-+{
-+ struct rfcomm_dlc *d;
-+
-+ BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
-+
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (!d) {
-+ rfcomm_send_dm(s, dlci);
-+ goto drop;
-+ }
-+
-+ if (pf && d->cfc) {
-+ u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
-+
-+ d->tx_credits += credits;
-+ if (d->tx_credits)
-+ clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ }
-+
-+ if (skb->len && d->state == BT_CONNECTED) {
-+ rfcomm_dlc_lock(d);
-+ d->rx_credits--;
-+ d->data_ready(d, skb);
-+ rfcomm_dlc_unlock(d);
-+ return 0;
-+ }
-+
-+drop:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
-+{
-+ struct rfcomm_hdr *hdr = (void *) skb->data;
-+ u8 type, dlci, fcs;
-+
-+ dlci = __get_dlci(hdr->addr);
-+ type = __get_type(hdr->ctrl);
-+
-+ /* Trim FCS */
-+ skb->len--; skb->tail--;
-+ fcs = *(u8 *) skb->tail;
-+
-+ if (__check_fcs(skb->data, type, fcs)) {
-+ BT_ERR("bad checksum in packet");
-+ kfree_skb(skb);
-+ return -EILSEQ;
-+ }
-+
-+ if (__test_ea(hdr->len))
-+ skb_pull(skb, 3);
-+ else
-+ skb_pull(skb, 4);
-+
-+ switch (type) {
-+ case RFCOMM_SABM:
-+ if (__test_pf(hdr->ctrl))
-+ rfcomm_recv_sabm(s, dlci);
-+ break;
-+
-+ case RFCOMM_DISC:
-+ if (__test_pf(hdr->ctrl))
-+ rfcomm_recv_disc(s, dlci);
-+ break;
-+
-+ case RFCOMM_UA:
-+ if (__test_pf(hdr->ctrl))
-+ rfcomm_recv_ua(s, dlci);
-+ break;
-+
-+ case RFCOMM_DM:
-+ rfcomm_recv_dm(s, dlci);
-+ break;
-+
-+ case RFCOMM_UIH:
-+ if (dlci)
-+ return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-+
-+ rfcomm_recv_mcc(s, skb);
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown packet type 0x%02x\n", type);
-+ break;
-+ }
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+/* ---- Connection and data processing ---- */
-+
-+static void rfcomm_process_connect(struct rfcomm_session *s)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("session %p state %ld", s, s->state);
-+
-+ list_for_each_safe(p, n, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ if (d->state == BT_CONFIG) {
-+ d->mtu = s->mtu;
-+ rfcomm_send_pn(s, 1, d);
-+ }
-+ }
-+}
-+
-+/* Send data queued for the DLC.
-+ * Return number of frames left in the queue.
-+ */
-+static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
-+{
-+ struct sk_buff *skb;
-+ int err;
-+
-+ BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d",
-+ d, d->state, d->cfc, d->rx_credits, d->tx_credits);
-+
-+ /* Send pending MSC */
-+ if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
-+ rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
-+
-+ if (d->cfc) {
-+ /* CFC enabled.
-+ * Give them some credits */
-+ if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
-+ d->rx_credits <= (d->cfc >> 2)) {
-+ rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
-+ d->rx_credits = d->cfc;
-+ }
-+ } else {
-+ /* CFC disabled.
-+ * Give ourselves some credits */
-+ d->tx_credits = 5;
-+ }
-+
-+ if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
-+ return skb_queue_len(&d->tx_queue);
-+
-+ while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-+ err = rfcomm_send_frame(d->session, skb->data, skb->len);
-+ if (err < 0) {
-+ skb_queue_head(&d->tx_queue, skb);
-+ break;
-+ }
-+ kfree_skb(skb);
-+ d->tx_credits--;
-+ }
-+
-+ if (d->cfc && !d->tx_credits) {
-+ /* We're out of TX credits.
-+ * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ }
-+
-+ return skb_queue_len(&d->tx_queue);
-+}
-+
-+static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("session %p state %ld", s, s->state);
-+
-+ list_for_each_safe(p, n, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
-+ __rfcomm_dlc_close(d, ETIMEDOUT);
-+ continue;
-+ }
-+
-+ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
-+ continue;
-+
-+ if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
-+ d->mscex == RFCOMM_MSCEX_OK)
-+ rfcomm_process_tx(d);
-+ }
-+}
-+
-+static inline void rfcomm_process_rx(struct rfcomm_session *s)
-+{
-+ struct socket *sock = s->sock;
-+ struct sock *sk = sock->sk;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
-+
-+ /* Get data directly from socket receive queue without copying it. */
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ rfcomm_recv_frame(s, skb);
-+ }
-+
-+ if (sk->state == BT_CLOSED) {
-+ if (!s->initiator)
-+ rfcomm_session_put(s);
-+
-+ rfcomm_session_close(s, sk->err);
-+ }
-+}
-+
-+static inline void rfcomm_accept_connection(struct rfcomm_session *s)
-+{
-+ struct socket *sock = s->sock, *nsock;
-+ int err;
-+
-+ /* Fast check for a new connection.
-+ * Avoids unnesesary socket allocations. */
-+ if (list_empty(&bluez_pi(sock->sk)->accept_q))
-+ return;
-+
-+ BT_DBG("session %p", s);
-+
-+ nsock = sock_alloc();
-+ if (!nsock)
-+ return;
-+
-+ nsock->type = sock->type;
-+ nsock->ops = sock->ops;
-+
-+ err = sock->ops->accept(sock, nsock, O_NONBLOCK);
-+ if (err < 0) {
-+ sock_release(nsock);
-+ return;
-+ }
-+
-+ /* Set our callbacks */
-+ nsock->sk->data_ready = rfcomm_l2data_ready;
-+ nsock->sk->state_change = rfcomm_l2state_change;
-+
-+ s = rfcomm_session_add(nsock, BT_OPEN);
-+ if (s) {
-+ rfcomm_session_hold(s);
-+ rfcomm_schedule(RFCOMM_SCHED_RX);
-+ } else
-+ sock_release(nsock);
-+}
-+
-+static inline void rfcomm_check_connection(struct rfcomm_session *s)
-+{
-+ struct sock *sk = s->sock->sk;
-+
-+ BT_DBG("%p state %ld", s, s->state);
-+
-+ switch(sk->state) {
-+ case BT_CONNECTED:
-+ s->state = BT_CONNECT;
-+
-+ /* We can adjust MTU on outgoing sessions.
-+ * L2CAP MTU minus UIH header and FCS. */
-+ s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
-+
-+ rfcomm_send_sabm(s, 0);
-+ break;
-+
-+ case BT_CLOSED:
-+ s->state = BT_CLOSED;
-+ rfcomm_session_close(s, sk->err);
-+ break;
-+ }
-+}
-+
-+static inline void rfcomm_process_sessions(void)
-+{
-+ struct list_head *p, *n;
-+
-+ rfcomm_lock();
-+
-+ list_for_each_safe(p, n, &session_list) {
-+ struct rfcomm_session *s;
-+ s = list_entry(p, struct rfcomm_session, list);
-+
-+ if (s->state == BT_LISTEN) {
-+ rfcomm_accept_connection(s);
-+ continue;
-+ }
-+
-+ rfcomm_session_hold(s);
-+
-+ switch (s->state) {
-+ case BT_BOUND:
-+ rfcomm_check_connection(s);
-+ break;
-+
-+ default:
-+ rfcomm_process_rx(s);
-+ break;
-+ }
-+
-+ rfcomm_process_dlcs(s);
-+
-+ rfcomm_session_put(s);
-+ }
-+
-+ rfcomm_unlock();
-+}
-+
-+static void rfcomm_worker(void)
-+{
-+ BT_DBG("");
-+
-+ daemonize(); reparent_to_init();
-+ set_fs(KERNEL_DS);
-+
-+ while (!atomic_read(&terminate)) {
-+ BT_DBG("worker loop event 0x%lx", rfcomm_event);
-+
-+ if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
-+ /* No pending events. Let's sleep.
-+ * Incomming connections and data will wake us up. */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule();
-+ }
-+
-+ /* Process stuff */
-+ clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-+ rfcomm_process_sessions();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ return;
-+}
-+
-+static int rfcomm_add_listener(bdaddr_t *ba)
-+{
-+ struct sockaddr_l2 addr;
-+ struct l2cap_options opts;
-+ struct socket *sock;
-+ struct rfcomm_session *s;
-+ int size, err = 0;
-+
-+ /* Create socket */
-+ err = rfcomm_l2sock_create(&sock);
-+ if (err < 0) {
-+ BT_ERR("Create socket failed %d", err);
-+ return err;
-+ }
-+
-+ /* Bind socket */
-+ bacpy(&addr.l2_bdaddr, ba);
-+ addr.l2_family = AF_BLUETOOTH;
-+ addr.l2_psm = htobs(RFCOMM_PSM);
-+ err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-+ if (err < 0) {
-+ BT_ERR("Bind failed %d", err);
-+ goto failed;
-+ }
-+
-+ /* Set L2CAP options */
-+ size = sizeof(opts);
-+ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
-+
-+ opts.imtu = RFCOMM_MAX_L2CAP_MTU;
-+ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
-+
-+ /* Start listening on the socket */
-+ err = sock->ops->listen(sock, 10);
-+ if (err) {
-+ BT_ERR("Listen failed %d", err);
-+ goto failed;
-+ }
-+
-+ /* Add listening session */
-+ s = rfcomm_session_add(sock, BT_LISTEN);
-+ if (!s)
-+ goto failed;
-+
-+ rfcomm_session_hold(s);
-+ return 0;
-+failed:
-+ sock_release(sock);
-+ return err;
-+}
-+
-+static void rfcomm_kill_listener(void)
-+{
-+ struct rfcomm_session *s;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("");
-+
-+ list_for_each_safe(p, n, &session_list) {
-+ s = list_entry(p, struct rfcomm_session, list);
-+ rfcomm_session_del(s);
-+ }
-+}
-+
-+static int rfcomm_run(void *unused)
-+{
-+ rfcomm_thread = current;
-+
-+ atomic_inc(&running);
-+
-+ daemonize(); reparent_to_init();
-+
-+ sigfillset(&current->blocked);
-+ set_fs(KERNEL_DS);
-+
-+ sprintf(current->comm, "krfcommd");
-+
-+ BT_DBG("");
-+
-+ rfcomm_add_listener(BDADDR_ANY);
-+
-+ rfcomm_worker();
-+
-+ rfcomm_kill_listener();
-+
-+ atomic_dec(&running);
-+ return 0;
-+}
-+
-+/* ---- Proc fs support ---- */
-+static int rfcomm_dlc_dump(char *buf)
-+{
-+ struct rfcomm_session *s;
-+ struct sock *sk;
-+ struct list_head *p, *pp;
-+ char *ptr = buf;
-+
-+ rfcomm_lock();
-+
-+ list_for_each(p, &session_list) {
-+ s = list_entry(p, struct rfcomm_session, list);
-+ sk = s->sock->sk;
-+
-+ list_for_each(pp, &s->dlcs) {
-+ struct rfcomm_dlc *d;
-+ d = list_entry(pp, struct rfcomm_dlc, list);
-+
-+ ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
-+ }
-+ }
-+
-+ rfcomm_unlock();
-+
-+ return ptr - buf;
-+}
-+
-+extern int rfcomm_sock_dump(char *buf);
-+
-+static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+ char *ptr = buf;
-+ int len;
-+
-+ BT_DBG("count %d, offset %ld", count, offset);
-+
-+ ptr += rfcomm_dlc_dump(ptr);
-+ ptr += rfcomm_sock_dump(ptr);
-+ len = ptr - buf;
-+
-+ if (len <= count + offset)
-+ *eof = 1;
-+
-+ *start = buf + offset;
-+ len -= offset;
-+
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+
-+/* ---- Initialization ---- */
-+int __init rfcomm_init(void)
-+{
-+ l2cap_load();
-+
-+ kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+
-+ rfcomm_init_sockets();
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+ rfcomm_init_ttys();
-+#endif
-+
-+ create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
-+
-+ BT_INFO("BlueZ RFCOMM ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
-+ return 0;
-+}
-+
-+void rfcomm_cleanup(void)
-+{
-+ /* Terminate working thread.
-+ * ie. Set terminate flag and wake it up */
-+ atomic_inc(&terminate);
-+ rfcomm_schedule(RFCOMM_SCHED_STATE);
-+
-+ /* Wait until thread is running */
-+ while (atomic_read(&running))
-+ schedule();
-+
-+ remove_proc_entry("bluetooth/rfcomm", NULL);
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+ rfcomm_cleanup_ttys();
-+#endif
-+
-+ rfcomm_cleanup_sockets();
-+ return;
-+}
-+
-+module_init(rfcomm_init);
-+module_exit(rfcomm_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/crc.c linux-2.4.18-mh15/net/bluetooth/rfcomm/crc.c
---- linux-2.4.18/net/bluetooth/rfcomm/crc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/rfcomm/crc.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,71 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * RFCOMM FCS calculation.
-+ *
-+ * $Id$
-+ */
-+
-+/* reversed, 8-bit, poly=0x07 */
-+unsigned char rfcomm_crc_table[256] = {
-+ 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
-+ 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
-+ 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
-+ 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
-+
-+ 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
-+ 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
-+ 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
-+ 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
-+
-+ 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
-+ 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
-+ 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
-+ 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
-+
-+ 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
-+ 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
-+ 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
-+ 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
-+
-+ 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
-+ 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
-+ 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
-+ 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
-+
-+ 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
-+ 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
-+ 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
-+ 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
-+
-+ 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
-+ 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
-+ 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
-+ 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
-+
-+ 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
-+ 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
-+ 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
-+ 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
-+};
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/Makefile linux-2.4.18-mh15/net/bluetooth/rfcomm/Makefile
---- linux-2.4.18/net/bluetooth/rfcomm/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/rfcomm/Makefile 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,11 @@
-+#
-+# Makefile for the Linux Bluetooth RFCOMM layer
-+#
-+
-+O_TARGET := rfcomm.o
-+
-+obj-y := core.o sock.o crc.o
-+obj-$(CONFIG_BLUEZ_RFCOMM_TTY) += tty.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/sock.c linux-2.4.18-mh15/net/bluetooth/rfcomm/sock.c
---- linux-2.4.18/net/bluetooth/rfcomm/sock.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/rfcomm/sock.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,847 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * RFCOMM sockets.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static struct proto_ops rfcomm_sock_ops;
-+
-+static struct bluez_sock_list rfcomm_sk_list = {
-+ lock: RW_LOCK_UNLOCKED
-+};
-+
-+static void rfcomm_sock_close(struct sock *sk);
-+static void rfcomm_sock_kill(struct sock *sk);
-+
-+/* ---- DLC callbacks ----
-+ *
-+ * called under rfcomm_dlc_lock()
-+ */
-+static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
-+{
-+ struct sock *sk = d->owner;
-+ if (!sk)
-+ return;
-+
-+ atomic_add(skb->len, &sk->rmem_alloc);
-+ skb_queue_tail(&sk->receive_queue, skb);
-+ sk->data_ready(sk, skb->len);
-+
-+ if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
-+ rfcomm_dlc_throttle(d);
-+}
-+
-+static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
-+{
-+ struct sock *sk = d->owner, *parent;
-+ if (!sk)
-+ return;
-+
-+ BT_DBG("dlc %p state %ld err %d", d, d->state, err);
-+
-+ bh_lock_sock(sk);
-+
-+ if (err)
-+ sk->err = err;
-+ sk->state = d->state;
-+
-+ parent = bluez_pi(sk)->parent;
-+ if (!parent) {
-+ if (d->state == BT_CONNECTED)
-+ rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
-+ sk->state_change(sk);
-+ } else
-+ parent->data_ready(parent, 0);
-+
-+ bh_unlock_sock(sk);
-+}
-+
-+/* ---- Socket functions ---- */
-+static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
-+{
-+ struct sock *sk;
-+
-+ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
-+ if (rfcomm_pi(sk)->channel == channel &&
-+ !bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+ }
-+
-+ return sk;
-+}
-+
-+/* Find socket with channel and source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-+{
-+ struct sock *sk, *sk1 = NULL;
-+
-+ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
-+ if (state && sk->state != state)
-+ continue;
-+
-+ if (rfcomm_pi(sk)->channel == channel) {
-+ /* Exact match. */
-+ if (!bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+
-+ /* Closest match */
-+ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ sk1 = sk;
-+ }
-+ }
-+ return sk ? sk : sk1;
-+}
-+
-+/* Find socket with given address (channel, src).
-+ * Returns locked socket */
-+static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-+{
-+ struct sock *s;
-+ read_lock(&rfcomm_sk_list.lock);
-+ s = __rfcomm_get_sock_by_channel(state, channel, src);
-+ if (s) bh_lock_sock(s);
-+ read_unlock(&rfcomm_sk_list.lock);
-+ return s;
-+}
-+
-+static void rfcomm_sock_destruct(struct sock *sk)
-+{
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+
-+ BT_DBG("sk %p dlc %p", sk, d);
-+
-+ skb_queue_purge(&sk->receive_queue);
-+ skb_queue_purge(&sk->write_queue);
-+
-+ rfcomm_dlc_lock(d);
-+ rfcomm_pi(sk)->dlc = NULL;
-+
-+ /* Detach DLC if it's owned by this socket */
-+ if (d->owner == sk)
-+ d->owner = NULL;
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_dlc_put(d);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void rfcomm_sock_cleanup_listen(struct sock *parent)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ /* Close not yet accepted dlcs */
-+ while ((sk = bluez_accept_dequeue(parent, NULL))) {
-+ rfcomm_sock_close(sk);
-+ rfcomm_sock_kill(sk);
-+ }
-+
-+ parent->state = BT_CLOSED;
-+ parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_kill(struct sock *sk)
-+{
-+ if (!sk->zapped || sk->socket)
-+ return;
-+
-+ BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
-+
-+ /* Kill poor orphan */
-+ bluez_sock_unlink(&rfcomm_sk_list, sk);
-+ sk->dead = 1;
-+ sock_put(sk);
-+}
-+
-+static void __rfcomm_sock_close(struct sock *sk)
-+{
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+
-+ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-+
-+ switch (sk->state) {
-+ case BT_LISTEN:
-+ rfcomm_sock_cleanup_listen(sk);
-+ break;
-+
-+ case BT_CONNECT:
-+ case BT_CONNECT2:
-+ case BT_CONFIG:
-+ case BT_CONNECTED:
-+ rfcomm_dlc_close(d, 0);
-+
-+ default:
-+ sk->zapped = 1;
-+ break;
-+ }
-+}
-+
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_close(struct sock *sk)
-+{
-+ lock_sock(sk);
-+ __rfcomm_sock_close(sk);
-+ release_sock(sk);
-+}
-+
-+static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ if (parent)
-+ sk->type = parent->type;
-+}
-+
-+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+ struct rfcomm_dlc *d;
-+ struct sock *sk;
-+
-+ sk = sk_alloc(PF_BLUETOOTH, prio, 1);
-+ if (!sk)
-+ return NULL;
-+
-+ d = rfcomm_dlc_alloc(prio);
-+ if (!d) {
-+ sk_free(sk);
-+ return NULL;
-+ }
-+ d->data_ready = rfcomm_sk_data_ready;
-+ d->state_change = rfcomm_sk_state_change;
-+
-+ rfcomm_pi(sk)->dlc = d;
-+ d->owner = sk;
-+
-+ bluez_sock_init(sock, sk);
-+
-+ sk->zapped = 0;
-+
-+ sk->destruct = rfcomm_sock_destruct;
-+ sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
-+
-+ sk->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-+ sk->rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-+
-+ sk->protocol = proto;
-+ sk->state = BT_OPEN;
-+
-+ bluez_sock_link(&rfcomm_sk_list, sk);
-+
-+ BT_DBG("sk %p", sk);
-+
-+ MOD_INC_USE_COUNT;
-+ return sk;
-+}
-+
-+static int rfcomm_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ sock->state = SS_UNCONNECTED;
-+
-+ if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &rfcomm_sock_ops;
-+
-+ if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ rfcomm_sock_init(sk, NULL);
-+ return 0;
-+}
-+
-+static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
-+
-+ if (!addr || addr->sa_family != AF_BLUETOOTH)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_OPEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ write_lock_bh(&rfcomm_sk_list.lock);
-+
-+ if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
-+ err = -EADDRINUSE;
-+ } else {
-+ /* Save source address */
-+ bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
-+ rfcomm_pi(sk)->channel = sa->rc_channel;
-+ sk->state = BT_BOUND;
-+ }
-+
-+ write_unlock_bh(&rfcomm_sk_list.lock);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+ struct sock *sk = sock->sk;
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
-+ return -EINVAL;
-+
-+ if (sk->state != BT_OPEN && sk->state != BT_BOUND)
-+ return -EBADFD;
-+
-+ if (sk->type != SOCK_STREAM)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ sk->state = BT_CONNECT;
-+ bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
-+ rfcomm_pi(sk)->channel = sa->rc_channel;
-+
-+ err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
-+ if (!err)
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int rfcomm_sock_listen(struct socket *sock, int backlog)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_BOUND) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ sk->max_ack_backlog = backlog;
-+ sk->ack_backlog = 0;
-+ sk->state = BT_LISTEN;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct sock *sk = sock->sk, *nsk;
-+ long timeo;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+ BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+ /* Wait for an incoming connection. (wake-one). */
-+ add_wait_queue_exclusive(sk->sleep, &wait);
-+ while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ if (err)
-+ goto done;
-+
-+ newsock->state = SS_CONNECTED;
-+
-+ BT_DBG("new socket %p", nsk);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ sa->rc_family = AF_BLUETOOTH;
-+ sa->rc_channel = rfcomm_pi(sk)->channel;
-+ if (peer)
-+ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
-+ else
-+ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
-+
-+ *len = sizeof(struct sockaddr_rc);
-+ return 0;
-+}
-+
-+static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-+ struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+ struct sk_buff *skb;
-+ int err, size;
-+ int sent = 0;
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ if (sk->shutdown & SEND_SHUTDOWN)
-+ return -EPIPE;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ lock_sock(sk);
-+
-+ while (len) {
-+ size = min_t(uint, len, d->mtu);
-+
-+ skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
-+ msg->msg_flags & MSG_DONTWAIT, &err);
-+ if (!skb)
-+ break;
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
-+ if (err) {
-+ kfree_skb(skb);
-+ sent = err;
-+ break;
-+ }
-+
-+ err = rfcomm_dlc_send(d, skb);
-+ if (err < 0) {
-+ kfree_skb(skb);
-+ break;
-+ }
-+
-+ sent += size;
-+ len -= size;
-+ }
-+
-+ release_sock(sk);
-+
-+ return sent ? sent : err;
-+}
-+
-+static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ add_wait_queue(sk->sleep, &wait);
-+ for (;;) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
-+ signal_pending(current) || !timeo)
-+ break;
-+
-+ set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-+ }
-+
-+ __set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+ return timeo;
-+}
-+
-+static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-+ int flags, struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ int target, err = 0, copied = 0;
-+ long timeo;
-+
-+ if (flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ msg->msg_namelen = 0;
-+
-+ BT_DBG("sk %p size %d", sk, size);
-+
-+ lock_sock(sk);
-+
-+ target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
-+ timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-+
-+ do {
-+ struct sk_buff *skb;
-+ int chunk;
-+
-+ skb = skb_dequeue(&sk->receive_queue);
-+ if (!skb) {
-+ if (copied >= target)
-+ break;
-+
-+ if ((err = sock_error(sk)) != 0)
-+ break;
-+ if (sk->shutdown & RCV_SHUTDOWN)
-+ break;
-+
-+ err = -EAGAIN;
-+ if (!timeo)
-+ break;
-+
-+ timeo = rfcomm_sock_data_wait(sk, timeo);
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ goto out;
-+ }
-+ continue;
-+ }
-+
-+ chunk = min_t(unsigned int, skb->len, size);
-+ if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
-+ skb_queue_head(&sk->receive_queue, skb);
-+ if (!copied)
-+ copied = -EFAULT;
-+ break;
-+ }
-+ copied += chunk;
-+ size -= chunk;
-+
-+ if (!(flags & MSG_PEEK)) {
-+ atomic_sub(chunk, &sk->rmem_alloc);
-+
-+ skb_pull(skb, chunk);
-+ if (skb->len) {
-+ skb_queue_head(&sk->receive_queue, skb);
-+ break;
-+ }
-+ kfree_skb(skb);
-+
-+ } else {
-+ /* put message back and return */
-+ skb_queue_head(&sk->receive_queue, skb);
-+ break;
-+ }
-+ } while (size);
-+
-+out:
-+ if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
-+ rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
-+
-+ release_sock(sk);
-+ return copied ? : err;
-+}
-+
-+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ int len, err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (get_user(len, optlen))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct sock *sk = sock->sk;
-+ int err;
-+
-+ lock_sock(sk);
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+ err = rfcomm_dev_ioctl(sk, cmd, arg);
-+#else
-+ err = -EOPNOTSUPP;
-+#endif
-+
-+ release_sock(sk);
-+
-+ return err;
-+}
-+
-+static int rfcomm_sock_shutdown(struct socket *sock, int how)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ lock_sock(sk);
-+ if (!sk->shutdown) {
-+ sk->shutdown = SHUTDOWN_MASK;
-+ __rfcomm_sock_close(sk);
-+
-+ if (sk->linger)
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ }
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ err = rfcomm_sock_shutdown(sock, 2);
-+
-+ sock_orphan(sk);
-+ rfcomm_sock_kill(sk);
-+ return err;
-+}
-+
-+/* ---- RFCOMM core layer callbacks ----
-+ *
-+ * called under rfcomm_lock()
-+ */
-+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
-+{
-+ struct sock *sk, *parent;
-+ bdaddr_t src, dst;
-+ int result = 0;
-+
-+ BT_DBG("session %p channel %d", s, channel);
-+
-+ rfcomm_session_getaddr(s, &src, &dst);
-+
-+ /* Check if we have socket listening on this channel */
-+ parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
-+ if (!parent)
-+ return 0;
-+
-+ /* Check for backlog size */
-+ if (parent->ack_backlog > parent->max_ack_backlog) {
-+ BT_DBG("backlog full %d", parent->ack_backlog);
-+ goto done;
-+ }
-+
-+ sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
-+ if (!sk)
-+ goto done;
-+
-+ rfcomm_sock_init(sk, parent);
-+ bacpy(&bluez_pi(sk)->src, &src);
-+ bacpy(&bluez_pi(sk)->dst, &dst);
-+ rfcomm_pi(sk)->channel = channel;
-+
-+ sk->state = BT_CONFIG;
-+ bluez_accept_enqueue(parent, sk);
-+
-+ /* Accept connection and return socket DLC */
-+ *d = rfcomm_pi(sk)->dlc;
-+ result = 1;
-+
-+done:
-+ bh_unlock_sock(parent);
-+ return result;
-+}
-+
-+/* ---- Proc fs support ---- */
-+int rfcomm_sock_dump(char *buf)
-+{
-+ struct bluez_sock_list *list = &rfcomm_sk_list;
-+ struct rfcomm_pinfo *pi;
-+ struct sock *sk;
-+ char *ptr = buf;
-+
-+ write_lock_bh(&list->lock);
-+
-+ for (sk = list->head; sk; sk = sk->next) {
-+ pi = rfcomm_pi(sk);
-+ ptr += sprintf(ptr, "sk %s %s %d %d\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ sk->state, rfcomm_pi(sk)->channel);
-+ }
-+
-+ write_unlock_bh(&list->lock);
-+
-+ return ptr - buf;
-+}
-+
-+static struct proto_ops rfcomm_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: rfcomm_sock_release,
-+ bind: rfcomm_sock_bind,
-+ connect: rfcomm_sock_connect,
-+ listen: rfcomm_sock_listen,
-+ accept: rfcomm_sock_accept,
-+ getname: rfcomm_sock_getname,
-+ sendmsg: rfcomm_sock_sendmsg,
-+ recvmsg: rfcomm_sock_recvmsg,
-+ shutdown: rfcomm_sock_shutdown,
-+ setsockopt: rfcomm_sock_setsockopt,
-+ getsockopt: rfcomm_sock_getsockopt,
-+ ioctl: rfcomm_sock_ioctl,
-+ poll: bluez_sock_poll,
-+ socketpair: sock_no_socketpair,
-+ mmap: sock_no_mmap
-+};
-+
-+static struct net_proto_family rfcomm_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: rfcomm_sock_create
-+};
-+
-+int rfcomm_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
-+ BT_ERR("Can't register RFCOMM socket layer");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+void rfcomm_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ /* Unregister socket, protocol and notifier */
-+ if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
-+ BT_ERR("Can't unregister RFCOMM socket layer %d", err);
-+}
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/tty.c linux-2.4.18-mh15/net/bluetooth/rfcomm/tty.c
---- linux-2.4.18/net/bluetooth/rfcomm/tty.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/rfcomm/tty.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,960 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * RFCOMM TTY.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+
-+#include <linux/slab.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */
-+#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */
-+#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
-+#define RFCOMM_TTY_MINOR 0
-+
-+struct rfcomm_dev {
-+ struct list_head list;
-+ atomic_t refcnt;
-+
-+ char name[12];
-+ int id;
-+ unsigned long flags;
-+ int opened;
-+ int err;
-+
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+ u8 channel;
-+
-+ uint modem_status;
-+
-+ struct rfcomm_dlc *dlc;
-+ struct tty_struct *tty;
-+ wait_queue_head_t wait;
-+ struct tasklet_struct wakeup_task;
-+
-+ atomic_t wmem_alloc;
-+};
-+
-+static LIST_HEAD(rfcomm_dev_list);
-+static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
-+
-+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
-+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
-+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
-+
-+static void rfcomm_tty_wakeup(unsigned long arg);
-+
-+/* ---- Device functions ---- */
-+static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
-+{
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+
-+ BT_DBG("dev %p dlc %p", dev, dlc);
-+
-+ rfcomm_dlc_lock(dlc);
-+ /* Detach DLC if it's owned by this dev */
-+ if (dlc->owner == dev)
-+ dlc->owner = NULL;
-+ rfcomm_dlc_unlock(dlc);
-+
-+ rfcomm_dlc_put(dlc);
-+ kfree(dev);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-+{
-+ atomic_inc(&dev->refcnt);
-+}
-+
-+static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-+{
-+ /* The reason this isn't actually a race, as you no
-+ doubt have a little voice screaming at you in your
-+ head, is that the refcount should never actually
-+ reach zero unless the device has already been taken
-+ off the list, in rfcomm_dev_del(). And if that's not
-+ true, we'll hit the BUG() in rfcomm_dev_destruct()
-+ anyway. */
-+ if (atomic_dec_and_test(&dev->refcnt))
-+ rfcomm_dev_destruct(dev);
-+}
-+
-+static struct rfcomm_dev *__rfcomm_dev_get(int id)
-+{
-+ struct rfcomm_dev *dev;
-+ struct list_head *p;
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ dev = list_entry(p, struct rfcomm_dev, list);
-+ if (dev->id == id)
-+ return dev;
-+ }
-+
-+ return NULL;
-+}
-+
-+static inline struct rfcomm_dev *rfcomm_dev_get(int id)
-+{
-+ struct rfcomm_dev *dev;
-+
-+ read_lock(&rfcomm_dev_lock);
-+
-+ dev = __rfcomm_dev_get(id);
-+ if (dev)
-+ rfcomm_dev_hold(dev);
-+
-+ read_unlock(&rfcomm_dev_lock);
-+
-+ return dev;
-+}
-+
-+static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
-+{
-+ struct rfcomm_dev *dev;
-+ struct list_head *head = &rfcomm_dev_list, *p;
-+ int err = 0;
-+
-+ BT_DBG("id %d channel %d", req->dev_id, req->channel);
-+
-+ dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+ memset(dev, 0, sizeof(struct rfcomm_dev));
-+
-+ write_lock_bh(&rfcomm_dev_lock);
-+
-+ if (req->dev_id < 0) {
-+ dev->id = 0;
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
-+ break;
-+
-+ dev->id++;
-+ head = p;
-+ }
-+ } else {
-+ dev->id = req->dev_id;
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
-+
-+ if (entry->id == dev->id) {
-+ err = -EADDRINUSE;
-+ goto out;
-+ }
-+
-+ if (entry->id > dev->id - 1)
-+ break;
-+
-+ head = p;
-+ }
-+ }
-+
-+ if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
-+ err = -ENFILE;
-+ goto out;
-+ }
-+
-+ sprintf(dev->name, "rfcomm%d", dev->id);
-+
-+ list_add(&dev->list, head);
-+ atomic_set(&dev->refcnt, 1);
-+
-+ bacpy(&dev->src, &req->src);
-+ bacpy(&dev->dst, &req->dst);
-+ dev->channel = req->channel;
-+
-+ dev->flags = req->flags &
-+ ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
-+
-+ init_waitqueue_head(&dev->wait);
-+ tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
-+
-+ rfcomm_dlc_lock(dlc);
-+ dlc->data_ready = rfcomm_dev_data_ready;
-+ dlc->state_change = rfcomm_dev_state_change;
-+ dlc->modem_status = rfcomm_dev_modem_status;
-+
-+ dlc->owner = dev;
-+ dev->dlc = dlc;
-+ rfcomm_dlc_unlock(dlc);
-+
-+ MOD_INC_USE_COUNT;
-+
-+out:
-+ write_unlock_bh(&rfcomm_dev_lock);
-+
-+ if (err) {
-+ kfree(dev);
-+ return err;
-+ } else
-+ return dev->id;
-+}
-+
-+static void rfcomm_dev_del(struct rfcomm_dev *dev)
-+{
-+ BT_DBG("dev %p", dev);
-+
-+ write_lock_bh(&rfcomm_dev_lock);
-+ list_del_init(&dev->list);
-+ write_unlock_bh(&rfcomm_dev_lock);
-+
-+ rfcomm_dev_put(dev);
-+}
-+
-+/* ---- Send buffer ---- */
-+
-+static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
-+{
-+ /* We can't let it be zero, because we don't get a callback
-+ when tx_credits becomes nonzero, hence we'd never wake up */
-+ return dlc->mtu * (dlc->tx_credits?:1);
-+}
-+
-+static void rfcomm_wfree(struct sk_buff *skb)
-+{
-+ struct rfcomm_dev *dev = (void *) skb->sk;
-+ atomic_sub(skb->truesize, &dev->wmem_alloc);
-+ if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-+ tasklet_schedule(&dev->wakeup_task);
-+ rfcomm_dev_put(dev);
-+}
-+
-+static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
-+{
-+ rfcomm_dev_hold(dev);
-+ atomic_add(skb->truesize, &dev->wmem_alloc);
-+ skb->sk = (void *) dev;
-+ skb->destructor = rfcomm_wfree;
-+}
-+
-+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority)
-+{
-+ if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
-+ struct sk_buff *skb = alloc_skb(size, priority);
-+ if (skb) {
-+ rfcomm_set_owner_w(skb, dev);
-+ return skb;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+/* ---- Device IOCTLs ---- */
-+
-+#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
-+
-+static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
-+{
-+ struct rfcomm_dev_req req;
-+ struct rfcomm_dlc *dlc;
-+ int id;
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
-+
-+ if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+
-+ if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
-+ /* Socket must be connected */
-+ if (sk->state != BT_CONNECTED)
-+ return -EBADFD;
-+
-+ dlc = rfcomm_pi(sk)->dlc;
-+ rfcomm_dlc_hold(dlc);
-+ } else {
-+ dlc = rfcomm_dlc_alloc(GFP_KERNEL);
-+ if (!dlc)
-+ return -ENOMEM;
-+ }
-+
-+ id = rfcomm_dev_add(&req, dlc);
-+ if (id < 0) {
-+ rfcomm_dlc_put(dlc);
-+ return id;
-+ }
-+
-+ if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
-+ /* DLC is now used by device.
-+ * Socket must be disconnected */
-+ sk->state = BT_CLOSED;
-+ }
-+
-+ return id;
-+}
-+
-+static int rfcomm_release_dev(unsigned long arg)
-+{
-+ struct rfcomm_dev_req req;
-+ struct rfcomm_dev *dev;
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
-+
-+ if (!(dev = rfcomm_dev_get(req.dev_id)))
-+ return -ENODEV;
-+
-+ if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
-+ rfcomm_dev_put(dev);
-+ return -EPERM;
-+ }
-+
-+ if (req.flags & (1 << RFCOMM_HANGUP_NOW))
-+ rfcomm_dlc_close(dev->dlc, 0);
-+
-+ rfcomm_dev_del(dev);
-+ rfcomm_dev_put(dev);
-+ return 0;
-+}
-+
-+static int rfcomm_get_dev_list(unsigned long arg)
-+{
-+ struct rfcomm_dev_list_req *dl;
-+ struct rfcomm_dev_info *di;
-+ struct list_head *p;
-+ int n = 0, size, err;
-+ u16 dev_num;
-+
-+ BT_DBG("");
-+
-+ if (get_user(dev_num, (u16 *) arg))
-+ return -EFAULT;
-+
-+ if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
-+ return -EINVAL;
-+
-+ size = sizeof(*dl) + dev_num * sizeof(*di);
-+
-+ if (!(dl = kmalloc(size, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ di = dl->dev_info;
-+
-+ read_lock_bh(&rfcomm_dev_lock);
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
-+ (di + n)->id = dev->id;
-+ (di + n)->flags = dev->flags;
-+ (di + n)->state = dev->dlc->state;
-+ (di + n)->channel = dev->channel;
-+ bacpy(&(di + n)->src, &dev->src);
-+ bacpy(&(di + n)->dst, &dev->dst);
-+ if (++n >= dev_num)
-+ break;
-+ }
-+
-+ read_unlock_bh(&rfcomm_dev_lock);
-+
-+ dl->dev_num = n;
-+ size = sizeof(*dl) + n * sizeof(*di);
-+
-+ err = copy_to_user((void *) arg, dl, size);
-+ kfree(dl);
-+
-+ return err ? -EFAULT : 0;
-+}
-+
-+static int rfcomm_get_dev_info(unsigned long arg)
-+{
-+ struct rfcomm_dev *dev;
-+ struct rfcomm_dev_info di;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ if (copy_from_user(&di, (void *)arg, sizeof(di)))
-+ return -EFAULT;
-+
-+ if (!(dev = rfcomm_dev_get(di.id)))
-+ return -ENODEV;
-+
-+ di.flags = dev->flags;
-+ di.channel = dev->channel;
-+ di.state = dev->dlc->state;
-+ bacpy(&di.src, &dev->src);
-+ bacpy(&di.dst, &dev->dst);
-+
-+ if (copy_to_user((void *)arg, &di, sizeof(di)))
-+ err = -EFAULT;
-+
-+ rfcomm_dev_put(dev);
-+ return err;
-+}
-+
-+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
-+{
-+ BT_DBG("cmd %d arg %ld", cmd, arg);
-+
-+ switch (cmd) {
-+ case RFCOMMCREATEDEV:
-+ return rfcomm_create_dev(sk, arg);
-+
-+ case RFCOMMRELEASEDEV:
-+ return rfcomm_release_dev(arg);
-+
-+ case RFCOMMGETDEVLIST:
-+ return rfcomm_get_dev_list(arg);
-+
-+ case RFCOMMGETDEVINFO:
-+ return rfcomm_get_dev_info(arg);
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+/* ---- DLC callbacks ---- */
-+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
-+{
-+ struct rfcomm_dev *dev = dlc->owner;
-+ struct tty_struct *tty;
-+
-+ if (!dev || !(tty = dev->tty)) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
-+
-+ if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-+ register int i;
-+ for (i = 0; i < skb->len; i++) {
-+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-+ tty_flip_buffer_push(tty);
-+
-+ tty_insert_flip_char(tty, skb->data[i], 0);
-+ }
-+ tty_flip_buffer_push(tty);
-+ } else
-+ tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
-+
-+ kfree_skb(skb);
-+}
-+
-+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
-+{
-+ struct rfcomm_dev *dev = dlc->owner;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
-+
-+ dev->err = err;
-+ wake_up_interruptible(&dev->wait);
-+
-+ if (dlc->state == BT_CLOSED) {
-+ if (!dev->tty) {
-+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-+ rfcomm_dev_hold(dev);
-+ rfcomm_dev_del(dev);
-+
-+ /* We have to drop DLC lock here, otherwise
-+ rfcomm_dev_put() will dead lock if it's
-+ the last reference. */
-+ rfcomm_dlc_unlock(dlc);
-+ rfcomm_dev_put(dev);
-+ rfcomm_dlc_lock(dlc);
-+ }
-+ } else
-+ tty_hangup(dev->tty);
-+ }
-+}
-+
-+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
-+{
-+ struct rfcomm_dev *dev = dlc->owner;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
-+
-+ dev->modem_status =
-+ ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
-+ ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
-+ ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) |
-+ ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0);
-+}
-+
-+/* ---- TTY functions ---- */
-+static void rfcomm_tty_wakeup(unsigned long arg)
-+{
-+ struct rfcomm_dev *dev = (void *) arg;
-+ struct tty_struct *tty = dev->tty;
-+ if (!tty)
-+ return;
-+
-+ BT_DBG("dev %p tty %p", dev, tty);
-+
-+ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-+ (tty->ldisc.write_wakeup)(tty);
-+
-+ wake_up_interruptible(&tty->write_wait);
-+#ifdef SERIAL_HAVE_POLL_WAIT
-+ wake_up_interruptible(&tty->poll_wait);
-+#endif
-+}
-+
-+static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct rfcomm_dev *dev;
-+ struct rfcomm_dlc *dlc;
-+ int err, id;
-+
-+ id = MINOR(tty->device) - tty->driver.minor_start;
-+
-+ BT_DBG("tty %p id %d", tty, id);
-+
-+ /* We don't leak this refcount. For reasons which are not entirely
-+ clear, the TTY layer will call our ->close() method even if the
-+ open fails. We decrease the refcount there, and decreasing it
-+ here too would cause breakage. */
-+ dev = rfcomm_dev_get(id);
-+ if (!dev)
-+ return -ENODEV;
-+
-+ BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
-+
-+ if (dev->opened++ != 0)
-+ return 0;
-+
-+ dlc = dev->dlc;
-+
-+ /* Attach TTY and open DLC */
-+
-+ rfcomm_dlc_lock(dlc);
-+ tty->driver_data = dev;
-+ dev->tty = tty;
-+ rfcomm_dlc_unlock(dlc);
-+ set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-+
-+ err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
-+ if (err < 0)
-+ return err;
-+
-+ /* Wait for DLC to connect */
-+ add_wait_queue(&dev->wait, &wait);
-+ while (1) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (dlc->state == BT_CLOSED) {
-+ err = -dev->err;
-+ break;
-+ }
-+
-+ if (dlc->state == BT_CONNECTED)
-+ break;
-+
-+ if (signal_pending(current)) {
-+ err = -EINTR;
-+ break;
-+ }
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&dev->wait, &wait);
-+
-+ return err;
-+}
-+
-+static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
-+
-+ if (--dev->opened == 0) {
-+ /* Close DLC and dettach TTY */
-+ rfcomm_dlc_close(dev->dlc, 0);
-+
-+ clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-+ tasklet_kill(&dev->wakeup_task);
-+
-+ rfcomm_dlc_lock(dev->dlc);
-+ tty->driver_data = NULL;
-+ dev->tty = NULL;
-+ rfcomm_dlc_unlock(dev->dlc);
-+ }
-+
-+ rfcomm_dev_put(dev);
-+}
-+
-+static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ struct sk_buff *skb;
-+ int err = 0, sent = 0, size;
-+
-+ BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
-+
-+ while (count) {
-+ size = min_t(uint, count, dlc->mtu);
-+
-+ if (from_user)
-+ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL);
-+ else
-+ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC);
-+
-+ if (!skb)
-+ break;
-+
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ if (from_user)
-+ copy_from_user(skb_put(skb, size), buf + sent, size);
-+ else
-+ memcpy(skb_put(skb, size), buf + sent, size);
-+
-+ if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
-+ kfree_skb(skb);
-+ break;
-+ }
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ return sent ? sent : err;
-+}
-+
-+static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("tty %p char %x", tty, ch);
-+
-+ skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC);
-+
-+ if (!skb)
-+ return;
-+
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ *(char *)skb_put(skb, 1) = ch;
-+
-+ if ((rfcomm_dlc_send(dlc, skb)) < 0)
-+ kfree_skb(skb);
-+}
-+
-+static int rfcomm_tty_write_room(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ int room;
-+
-+ BT_DBG("tty %p", tty);
-+
-+ room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
-+ if (room < 0)
-+ room = 0;
-+
-+ return room;
-+}
-+
-+static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
-+{
-+ u8 v24_sig, mask;
-+
-+ BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
-+
-+ if (cmd == TIOCMSET)
-+ v24_sig = 0;
-+ else
-+ rfcomm_dlc_get_modem_status(dlc, &v24_sig);
-+
-+ mask = ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
-+ ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
-+ ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
-+ ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
-+ ((status & TIOCM_RI) ? RFCOMM_V24_IC : 0) |
-+ ((status & TIOCM_CD) ? RFCOMM_V24_DV : 0);
-+
-+ if (cmd == TIOCMBIC)
-+ v24_sig &= ~mask;
-+ else
-+ v24_sig |= mask;
-+
-+ rfcomm_dlc_set_modem_status(dlc, v24_sig);
-+ return 0;
-+}
-+
-+static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ uint status;
-+ int err;
-+
-+ BT_DBG("tty %p cmd 0x%02x", tty, cmd);
-+
-+ switch (cmd) {
-+ case TCGETS:
-+ BT_DBG("TCGETS is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TCSETS:
-+ BT_DBG("TCSETS is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCMGET:
-+ BT_DBG("TIOCMGET");
-+
-+ return put_user(dev->modem_status, (unsigned int *)arg);
-+
-+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-+ case TIOCMBIS: /* Turns on the lines as specified by the mask */
-+ case TIOCMBIC: /* Turns off the lines as specified by the mask */
-+ if ((err = get_user(status, (unsigned int *)arg)))
-+ return err;
-+ return rfcomm_tty_set_modem_status(cmd, dlc, status);
-+
-+ case TIOCMIWAIT:
-+ BT_DBG("TIOCMIWAIT");
-+ break;
-+
-+ case TIOCGICOUNT:
-+ BT_DBG("TIOCGICOUNT");
-+ break;
-+
-+ case TIOCGSERIAL:
-+ BT_ERR("TIOCGSERIAL is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSSERIAL:
-+ BT_ERR("TIOCSSERIAL is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSERGSTRUCT:
-+ BT_ERR("TIOCSERGSTRUCT is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSERGETLSR:
-+ BT_ERR("TIOCSERGETLSR is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSERCONFIG:
-+ BT_ERR("TIOCSERCONFIG is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ default:
-+ return -ENOIOCTLCMD; /* ioctls which we must ignore */
-+
-+ }
-+
-+ return -ENOIOCTLCMD;
-+}
-+
-+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-+
-+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
-+{
-+ BT_DBG("tty %p", tty);
-+
-+ if ((tty->termios->c_cflag == old->c_cflag) &&
-+ (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
-+ return;
-+
-+ /* handle turning off CRTSCTS */
-+ if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
-+ BT_DBG("turning off CRTSCTS");
-+ }
-+}
-+
-+static void rfcomm_tty_throttle(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ rfcomm_dlc_throttle(dev->dlc);
-+}
-+
-+static void rfcomm_tty_unthrottle(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ rfcomm_dlc_unthrottle(dev->dlc);
-+}
-+
-+static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ if (skb_queue_len(&dlc->tx_queue))
-+ return dlc->mtu;
-+
-+ return 0;
-+}
-+
-+static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ skb_queue_purge(&dev->dlc->tx_queue);
-+
-+ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-+ tty->ldisc.write_wakeup(tty);
-+}
-+
-+static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
-+{
-+ BT_DBG("tty %p ch %c", tty, ch);
-+}
-+
-+static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-+{
-+ BT_DBG("tty %p timeout %d", tty, timeout);
-+}
-+
-+static void rfcomm_tty_hangup(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ rfcomm_tty_flush_buffer(tty);
-+
-+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
-+ rfcomm_dev_del(dev);
-+}
-+
-+static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
-+{
-+ return 0;
-+}
-+
-+/* ---- TTY structure ---- */
-+static int rfcomm_tty_refcount; /* If we manage several devices */
-+
-+static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
-+static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
-+static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
-+
-+static struct tty_driver rfcomm_tty_driver = {
-+ magic: TTY_DRIVER_MAGIC,
-+ driver_name: "rfcomm",
-+#ifdef CONFIG_DEVFS_FS
-+ name: "bluetooth/rfcomm/%d",
-+#else
-+ name: "rfcomm",
-+#endif
-+ major: RFCOMM_TTY_MAJOR,
-+ minor_start: RFCOMM_TTY_MINOR,
-+ num: RFCOMM_TTY_PORTS,
-+ type: TTY_DRIVER_TYPE_SERIAL,
-+ subtype: SERIAL_TYPE_NORMAL,
-+ flags: TTY_DRIVER_REAL_RAW,
-+
-+ refcount: &rfcomm_tty_refcount,
-+ table: rfcomm_tty_table,
-+ termios: rfcomm_tty_termios,
-+ termios_locked: rfcomm_tty_termios_locked,
-+
-+ open: rfcomm_tty_open,
-+ close: rfcomm_tty_close,
-+ put_char: rfcomm_tty_put_char,
-+ write: rfcomm_tty_write,
-+ write_room: rfcomm_tty_write_room,
-+ chars_in_buffer: rfcomm_tty_chars_in_buffer,
-+ flush_buffer: rfcomm_tty_flush_buffer,
-+ ioctl: rfcomm_tty_ioctl,
-+ throttle: rfcomm_tty_throttle,
-+ unthrottle: rfcomm_tty_unthrottle,
-+ set_termios: rfcomm_tty_set_termios,
-+ send_xchar: rfcomm_tty_send_xchar,
-+ stop: NULL,
-+ start: NULL,
-+ hangup: rfcomm_tty_hangup,
-+ wait_until_sent: rfcomm_tty_wait_until_sent,
-+ read_proc: rfcomm_tty_read_proc,
-+};
-+
-+int rfcomm_init_ttys(void)
-+{
-+ int i;
-+
-+ /* Initalize our global data */
-+ for (i = 0; i < RFCOMM_TTY_PORTS; i++)
-+ rfcomm_tty_table[i] = NULL;
-+
-+ /* Register the TTY driver */
-+ rfcomm_tty_driver.init_termios = tty_std_termios;
-+ rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-+ rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
-+
-+ if (tty_register_driver(&rfcomm_tty_driver)) {
-+ BT_ERR("Can't register RFCOMM TTY driver");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+void rfcomm_cleanup_ttys(void)
-+{
-+ tty_unregister_driver(&rfcomm_tty_driver);
-+ return;
-+}
-diff -urN linux-2.4.18/net/bluetooth/sco.c linux-2.4.18-mh15/net/bluetooth/sco.c
---- linux-2.4.18/net/bluetooth/sco.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18-mh15/net/bluetooth/sco.c 2004-08-01 16:26:23.000000000 +0200
-@@ -0,0 +1,1019 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ SCO sockets.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "0.3"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/sco.h>
-+
-+#ifndef SCO_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static struct proto_ops sco_sock_ops;
-+
-+static struct bluez_sock_list sco_sk_list = {
-+ lock: RW_LOCK_UNLOCKED
-+};
-+
-+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
-+static void sco_chan_del(struct sock *sk, int err);
-+static inline struct sock * sco_chan_get(struct sco_conn *conn);
-+
-+static int sco_conn_del(struct hci_conn *conn, int err);
-+
-+static void sco_sock_close(struct sock *sk);
-+static void sco_sock_kill(struct sock *sk);
-+
-+/* ----- SCO timers ------ */
-+static void sco_sock_timeout(unsigned long arg)
-+{
-+ struct sock *sk = (struct sock *) arg;
-+
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ bh_lock_sock(sk);
-+ sk->err = ETIMEDOUT;
-+ sk->state_change(sk);
-+ bh_unlock_sock(sk);
-+
-+ sco_sock_kill(sk);
-+ sock_put(sk);
-+}
-+
-+static void sco_sock_set_timer(struct sock *sk, long timeout)
-+{
-+ BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
-+
-+ if (!mod_timer(&sk->timer, jiffies + timeout))
-+ sock_hold(sk);
-+}
-+
-+static void sco_sock_clear_timer(struct sock *sk)
-+{
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-+ __sock_put(sk);
-+}
-+
-+static void sco_sock_init_timer(struct sock *sk)
-+{
-+ init_timer(&sk->timer);
-+ sk->timer.function = sco_sock_timeout;
-+ sk->timer.data = (unsigned long)sk;
-+}
-+
-+/* -------- SCO connections --------- */
-+static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
-+{
-+ struct hci_dev *hdev = hcon->hdev;
-+ struct sco_conn *conn;
-+
-+ if ((conn = hcon->sco_data))
-+ return conn;
-+
-+ if (status)
-+ return conn;
-+
-+ if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC)))
-+ return NULL;
-+ memset(conn, 0, sizeof(struct sco_conn));
-+
-+ spin_lock_init(&conn->lock);
-+
-+ hcon->sco_data = conn;
-+ conn->hcon = hcon;
-+
-+ conn->src = &hdev->bdaddr;
-+ conn->dst = &hcon->dst;
-+
-+ if (hdev->sco_mtu > 0)
-+ conn->mtu = hdev->sco_mtu;
-+ else
-+ conn->mtu = 60;
-+
-+ BT_DBG("hcon %p conn %p", hcon, conn);
-+
-+ MOD_INC_USE_COUNT;
-+ return conn;
-+}
-+
-+static int sco_conn_del(struct hci_conn *hcon, int err)
-+{
-+ struct sco_conn *conn;
-+ struct sock *sk;
-+
-+ if (!(conn = hcon->sco_data))
-+ return 0;
-+
-+ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-+
-+ /* Kill socket */
-+ if ((sk = sco_chan_get(conn))) {
-+ bh_lock_sock(sk);
-+ sco_sock_clear_timer(sk);
-+ sco_chan_del(sk, err);
-+ bh_unlock_sock(sk);
-+ sco_sock_kill(sk);
-+ }
-+
-+ hcon->sco_data = NULL;
-+ kfree(conn);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+int sco_connect(struct sock *sk)
-+{
-+ bdaddr_t *src = &bluez_pi(sk)->src;
-+ bdaddr_t *dst = &bluez_pi(sk)->dst;
-+ struct sco_conn *conn;
-+ struct hci_conn *hcon;
-+ struct hci_dev *hdev;
-+ int err = 0;
-+
-+ BT_DBG("%s -> %s", batostr(src), batostr(dst));
-+
-+ if (!(hdev = hci_get_route(dst, src)))
-+ return -EHOSTUNREACH;
-+
-+ hci_dev_lock_bh(hdev);
-+
-+ err = -ENOMEM;
-+
-+ hcon = hci_connect(hdev, SCO_LINK, dst);
-+ if (!hcon)
-+ goto done;
-+
-+ conn = sco_conn_add(hcon, 0);
-+ if (!conn) {
-+ hci_conn_put(hcon);
-+ goto done;
-+ }
-+
-+ /* Update source addr of the socket */
-+ bacpy(src, conn->src);
-+
-+ err = sco_chan_add(conn, sk, NULL);
-+ if (err)
-+ goto done;
-+
-+ if (hcon->state == BT_CONNECTED) {
-+ sco_sock_clear_timer(sk);
-+ sk->state = BT_CONNECTED;
-+ } else {
-+ sk->state = BT_CONNECT;
-+ sco_sock_set_timer(sk, sk->sndtimeo);
-+ }
-+done:
-+ hci_dev_unlock_bh(hdev);
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
-+static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
-+{
-+ struct sco_conn *conn = sco_pi(sk)->conn;
-+ struct sk_buff *skb;
-+ int err, count;
-+
-+ /* Check outgoing MTU */
-+ if (len > conn->mtu)
-+ return -EINVAL;
-+
-+ BT_DBG("sk %p len %d", sk, len);
-+
-+ count = MIN(conn->mtu, len);
-+ if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
-+ return err;
-+
-+ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-+ err = -EFAULT;
-+ goto fail;
-+ }
-+
-+ if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-+ goto fail;
-+
-+ return count;
-+
-+fail:
-+ kfree_skb(skb);
-+ return err;
-+}
-+
-+static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
-+{
-+ struct sock *sk = sco_chan_get(conn);
-+
-+ if (!sk)
-+ goto drop;
-+
-+ BT_DBG("sk %p len %d", sk, skb->len);
-+
-+ if (sk->state != BT_CONNECTED)
-+ goto drop;
-+
-+ if (!sock_queue_rcv_skb(sk, skb))
-+ return;
-+
-+drop:
-+ kfree_skb(skb);
-+ return;
-+}
-+
-+/* -------- Socket interface ---------- */
-+static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
-+{
-+ struct sock *sk;
-+
-+ for (sk = sco_sk_list.head; sk; sk = sk->next) {
-+ if (!bacmp(&bluez_pi(sk)->src, ba))
-+ break;
-+ }
-+
-+ return sk;
-+}
-+
-+/* Find socket listening on source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *sco_get_sock_listen(bdaddr_t *src)
-+{
-+ struct sock *sk, *sk1 = NULL;
-+
-+ read_lock(&sco_sk_list.lock);
-+
-+ for (sk = sco_sk_list.head; sk; sk = sk->next) {
-+ if (sk->state != BT_LISTEN)
-+ continue;
-+
-+ /* Exact match. */
-+ if (!bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+
-+ /* Closest match */
-+ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ sk1 = sk;
-+ }
-+
-+ read_unlock(&sco_sk_list.lock);
-+
-+ return sk ? sk : sk1;
-+}
-+
-+static void sco_sock_destruct(struct sock *sk)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ skb_queue_purge(&sk->receive_queue);
-+ skb_queue_purge(&sk->write_queue);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void sco_sock_cleanup_listen(struct sock *parent)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ /* Close not yet accepted channels */
-+ while ((sk = bluez_accept_dequeue(parent, NULL))) {
-+ sco_sock_close(sk);
-+ sco_sock_kill(sk);
-+ }
-+
-+ parent->state = BT_CLOSED;
-+ parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void sco_sock_kill(struct sock *sk)
-+{
-+ if (!sk->zapped || sk->socket)
-+ return;
-+
-+ BT_DBG("sk %p state %d", sk, sk->state);
-+
-+ /* Kill poor orphan */
-+ bluez_sock_unlink(&sco_sk_list, sk);
-+ sk->dead = 1;
-+ sock_put(sk);
-+}
-+
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void sco_sock_close(struct sock *sk)
-+{
-+ struct sco_conn *conn;
-+
-+ sco_sock_clear_timer(sk);
-+
-+ lock_sock(sk);
-+
-+ conn = sco_pi(sk)->conn;
-+
-+ BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
-+
-+ switch (sk->state) {
-+ case BT_LISTEN:
-+ sco_sock_cleanup_listen(sk);
-+ break;
-+
-+ case BT_CONNECTED:
-+ case BT_CONFIG:
-+ case BT_CONNECT:
-+ case BT_DISCONN:
-+ sco_chan_del(sk, ECONNRESET);
-+ break;
-+
-+ default:
-+ sk->zapped = 1;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+}
-+
-+static void sco_sock_init(struct sock *sk, struct sock *parent)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ if (parent)
-+ sk->type = parent->type;
-+}
-+
-+static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+ struct sock *sk;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-+ return NULL;
-+
-+ bluez_sock_init(sock, sk);
-+
-+ sk->zapped = 0;
-+
-+ sk->destruct = sco_sock_destruct;
-+ sk->sndtimeo = SCO_CONN_TIMEOUT;
-+
-+ sk->protocol = proto;
-+ sk->state = BT_OPEN;
-+
-+ sco_sock_init_timer(sk);
-+
-+ bluez_sock_link(&sco_sk_list, sk);
-+
-+ MOD_INC_USE_COUNT;
-+ return sk;
-+}
-+
-+static int sco_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ sock->state = SS_UNCONNECTED;
-+
-+ if (sock->type != SOCK_SEQPACKET)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &sco_sock_ops;
-+
-+ if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ sco_sock_init(sk, NULL);
-+ return 0;
-+}
-+
-+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+ struct sock *sk = sock->sk;
-+ bdaddr_t *src = &sa->sco_bdaddr;
-+ int err = 0;
-+
-+ BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
-+
-+ if (!addr || addr->sa_family != AF_BLUETOOTH)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_OPEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ write_lock_bh(&sco_sk_list.lock);
-+
-+ if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
-+ err = -EADDRINUSE;
-+ } else {
-+ /* Save source address */
-+ bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
-+ sk->state = BT_BOUND;
-+ }
-+
-+ write_unlock_bh(&sco_sk_list.lock);
-+
-+done:
-+ release_sock(sk);
-+
-+ return err;
-+}
-+
-+static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
-+ return -EINVAL;
-+
-+ if (sk->state != BT_OPEN && sk->state != BT_BOUND)
-+ return -EBADFD;
-+
-+ if (sk->type != SOCK_SEQPACKET)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ /* Set destination address and psm */
-+ bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);
-+
-+ if ((err = sco_connect(sk)))
-+ goto done;
-+
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_listen(struct socket *sock, int backlog)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ sk->max_ack_backlog = backlog;
-+ sk->ack_backlog = 0;
-+ sk->state = BT_LISTEN;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct sock *sk = sock->sk, *ch;
-+ long timeo;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+ BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+ /* Wait for an incoming connection. (wake-one). */
-+ add_wait_queue_exclusive(sk->sleep, &wait);
-+ while (!(ch = bluez_accept_dequeue(sk, newsock))) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ if (err)
-+ goto done;
-+
-+ newsock->state = SS_CONNECTED;
-+
-+ BT_DBG("new socket %p", ch);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ addr->sa_family = AF_BLUETOOTH;
-+ *len = sizeof(struct sockaddr_sco);
-+
-+ if (peer)
-+ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
-+ else
-+ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);
-+
-+ return 0;
-+}
-+
-+static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (sk->err)
-+ return sock_error(sk);
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state == BT_CONNECTED)
-+ err = sco_send_frame(sk, msg, len);
-+ else
-+ err = -ENOTCONN;
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ struct sco_options opts;
-+ struct sco_conninfo cinfo;
-+ int len, err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (get_user(len, optlen))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ case SCO_OPTIONS:
-+ if (sk->state != BT_CONNECTED) {
-+ err = -ENOTCONN;
-+ break;
-+ }
-+
-+ opts.mtu = sco_pi(sk)->conn->mtu;
-+
-+ BT_DBG("mtu %d", opts.mtu);
-+
-+ len = MIN(len, sizeof(opts));
-+ if (copy_to_user(optval, (char *)&opts, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ case SCO_CONNINFO:
-+ if (sk->state != BT_CONNECTED) {
-+ err = -ENOTCONN;
-+ break;
-+ }
-+
-+ cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
-+
-+ len = MIN(len, sizeof(cinfo));
-+ if (copy_to_user(optval, (char *)&cinfo, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int sco_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sco_sock_close(sk);
-+ if (sk->linger) {
-+ lock_sock(sk);
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ release_sock(sk);
-+ }
-+
-+ sock_orphan(sk);
-+ sco_sock_kill(sk);
-+ return err;
-+}
-+
-+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ BT_DBG("conn %p", conn);
-+
-+ sco_pi(sk)->conn = conn;
-+ conn->sk = sk;
-+
-+ if (parent)
-+ bluez_accept_enqueue(parent, sk);
-+}
-+
-+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ int err = 0;
-+
-+ sco_conn_lock(conn);
-+ if (conn->sk) {
-+ err = -EBUSY;
-+ } else {
-+ __sco_chan_add(conn, sk, parent);
-+ }
-+ sco_conn_unlock(conn);
-+ return err;
-+}
-+
-+static inline struct sock * sco_chan_get(struct sco_conn *conn)
-+{
-+ struct sock *sk = NULL;
-+ sco_conn_lock(conn);
-+ sk = conn->sk;
-+ sco_conn_unlock(conn);
-+ return sk;
-+}
-+
-+/* Delete channel.
-+ * Must be called on the locked socket. */
-+static void sco_chan_del(struct sock *sk, int err)
-+{
-+ struct sco_conn *conn;
-+
-+ conn = sco_pi(sk)->conn;
-+
-+ BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-+
-+ if (conn) {
-+ sco_conn_lock(conn);
-+ conn->sk = NULL;
-+ sco_pi(sk)->conn = NULL;
-+ sco_conn_unlock(conn);
-+ hci_conn_put(conn->hcon);
-+ }
-+
-+ sk->state = BT_CLOSED;
-+ sk->err = err;
-+ sk->state_change(sk);
-+
-+ sk->zapped = 1;
-+}
-+
-+static void sco_conn_ready(struct sco_conn *conn)
-+{
-+ struct sock *parent, *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ sco_conn_lock(conn);
-+
-+ if ((sk = conn->sk)) {
-+ sco_sock_clear_timer(sk);
-+ bh_lock_sock(sk);
-+ sk->state = BT_CONNECTED;
-+ sk->state_change(sk);
-+ bh_unlock_sock(sk);
-+ } else {
-+ parent = sco_get_sock_listen(conn->src);
-+ if (!parent)
-+ goto done;
-+
-+ bh_lock_sock(parent);
-+
-+ sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
-+ if (!sk) {
-+ bh_unlock_sock(parent);
-+ goto done;
-+ }
-+
-+ sco_sock_init(sk, parent);
-+
-+ bacpy(&bluez_pi(sk)->src, conn->src);
-+ bacpy(&bluez_pi(sk)->dst, conn->dst);
-+
-+ hci_conn_hold(conn->hcon);
-+ __sco_chan_add(conn, sk, parent);
-+
-+ sk->state = BT_CONNECTED;
-+
-+ /* Wake up parent */
-+ parent->data_ready(parent, 1);
-+
-+ bh_unlock_sock(parent);
-+ }
-+
-+done:
-+ sco_conn_unlock(conn);
-+}
-+
-+/* ----- SCO interface with lower layer (HCI) ----- */
-+int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-+
-+ /* Always accept connection */
-+ return HCI_LM_ACCEPT;
-+}
-+
-+int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-+
-+ if (hcon->type != SCO_LINK)
-+ return 0;
-+
-+ if (!status) {
-+ struct sco_conn *conn;
-+
-+ conn = sco_conn_add(hcon, status);
-+ if (conn)
-+ sco_conn_ready(conn);
-+ } else
-+ sco_conn_del(hcon, bterr(status));
-+
-+ return 0;
-+}
-+
-+int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
-+{
-+ BT_DBG("hcon %p reason %d", hcon, reason);
-+
-+ if (hcon->type != SCO_LINK)
-+ return 0;
-+
-+ sco_conn_del(hcon, bterr(reason));
-+ return 0;
-+}
-+
-+int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
-+{
-+ struct sco_conn *conn = hcon->sco_data;
-+
-+ if (!conn)
-+ goto drop;
-+
-+ BT_DBG("conn %p len %d", conn, skb->len);
-+
-+ if (skb->len) {
-+ sco_recv_frame(conn, skb);
-+ return 0;
-+ }
-+
-+drop:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+/* ----- Proc fs support ------ */
-+static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
-+{
-+ struct sco_pinfo *pi;
-+ struct sock *sk;
-+ char *ptr = buf;
-+
-+ write_lock_bh(&list->lock);
-+
-+ for (sk = list->head; sk; sk = sk->next) {
-+ pi = sco_pi(sk);
-+ ptr += sprintf(ptr, "%s %s %d\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ sk->state);
-+ }
-+
-+ write_unlock_bh(&list->lock);
-+
-+ ptr += sprintf(ptr, "\n");
-+
-+ return ptr - buf;
-+}
-+
-+static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+ char *ptr = buf;
-+ int len;
-+
-+ BT_DBG("count %d, offset %ld", count, offset);
-+
-+ ptr += sco_sock_dump(ptr, &sco_sk_list);
-+ len = ptr - buf;
-+
-+ if (len <= count + offset)
-+ *eof = 1;
-+
-+ *start = buf + offset;
-+ len -= offset;
-+
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+
-+static struct proto_ops sco_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: sco_sock_release,
-+ bind: sco_sock_bind,
-+ connect: sco_sock_connect,
-+ listen: sco_sock_listen,
-+ accept: sco_sock_accept,
-+ getname: sco_sock_getname,
-+ sendmsg: sco_sock_sendmsg,
-+ recvmsg: bluez_sock_recvmsg,
-+ poll: bluez_sock_poll,
-+ socketpair: sock_no_socketpair,
-+ ioctl: sock_no_ioctl,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sco_sock_setsockopt,
-+ getsockopt: sco_sock_getsockopt,
-+ mmap: sock_no_mmap
-+};
-+
-+static struct net_proto_family sco_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: sco_sock_create
-+};
-+
-+static struct hci_proto sco_hci_proto = {
-+ name: "SCO",
-+ id: HCI_PROTO_SCO,
-+ connect_ind: sco_connect_ind,
-+ connect_cfm: sco_connect_cfm,
-+ disconn_ind: sco_disconn_ind,
-+ recv_scodata: sco_recv_scodata,
-+};
-+
-+int __init sco_init(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
-+ BT_ERR("Can't register SCO socket layer");
-+ return err;
-+ }
-+
-+ if ((err = hci_register_proto(&sco_hci_proto))) {
-+ BT_ERR("Can't register SCO protocol");
-+ return err;
-+ }
-+
-+ create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
-+
-+ BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ return 0;
-+}
-+
-+void sco_cleanup(void)
-+{
-+ int err;
-+
-+ remove_proc_entry("bluetooth/sco", NULL);
-+
-+ /* Unregister socket, protocol and notifier */
-+ if ((err = bluez_sock_unregister(BTPROTO_SCO)))
-+ BT_ERR("Can't unregister SCO socket layer %d", err);
-+
-+ if ((err = hci_unregister_proto(&sco_hci_proto)))
-+ BT_ERR("Can't unregister SCO protocol %d", err);
-+}
-+
-+module_init(sco_init);
-+module_exit(sco_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/syms.c linux-2.4.18-mh15/net/bluetooth/syms.c
---- linux-2.4.18/net/bluetooth/syms.c 2001-09-07 18:28:38.000000000 +0200
-+++ linux-2.4.18-mh15/net/bluetooth/syms.c 2004-08-01 16:26:23.000000000 +0200
-@@ -25,7 +25,7 @@
- /*
- * BlueZ symbols.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
-@@ -39,25 +39,28 @@
- #include <linux/socket.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
-
- /* HCI Core */
- EXPORT_SYMBOL(hci_register_dev);
- EXPORT_SYMBOL(hci_unregister_dev);
-+EXPORT_SYMBOL(hci_suspend_dev);
-+EXPORT_SYMBOL(hci_resume_dev);
-+
- EXPORT_SYMBOL(hci_register_proto);
- EXPORT_SYMBOL(hci_unregister_proto);
--EXPORT_SYMBOL(hci_register_notifier);
--EXPORT_SYMBOL(hci_unregister_notifier);
-
-+EXPORT_SYMBOL(hci_get_route);
- EXPORT_SYMBOL(hci_connect);
--EXPORT_SYMBOL(hci_disconnect);
- EXPORT_SYMBOL(hci_dev_get);
-+EXPORT_SYMBOL(hci_conn_auth);
-+EXPORT_SYMBOL(hci_conn_encrypt);
-
- EXPORT_SYMBOL(hci_recv_frame);
- EXPORT_SYMBOL(hci_send_acl);
- EXPORT_SYMBOL(hci_send_sco);
--EXPORT_SYMBOL(hci_send_raw);
-+EXPORT_SYMBOL(hci_send_cmd);
-+EXPORT_SYMBOL(hci_si_event);
-
- /* BlueZ lib */
- EXPORT_SYMBOL(bluez_dump);
-@@ -68,5 +71,11 @@
- /* BlueZ sockets */
- EXPORT_SYMBOL(bluez_sock_register);
- EXPORT_SYMBOL(bluez_sock_unregister);
-+EXPORT_SYMBOL(bluez_sock_init);
- EXPORT_SYMBOL(bluez_sock_link);
- EXPORT_SYMBOL(bluez_sock_unlink);
-+EXPORT_SYMBOL(bluez_sock_recvmsg);
-+EXPORT_SYMBOL(bluez_sock_poll);
-+EXPORT_SYMBOL(bluez_accept_enqueue);
-+EXPORT_SYMBOL(bluez_accept_dequeue);
-+EXPORT_SYMBOL(bluez_sock_wait_state);
-diff -urN linux-2.4.18/net/netsyms.c linux-2.4.18-mh15/net/netsyms.c
---- linux-2.4.18/net/netsyms.c 2002-02-25 20:38:14.000000000 +0100
-+++ linux-2.4.18-mh15/net/netsyms.c 2004-08-01 16:26:23.000000000 +0200
-@@ -159,6 +159,7 @@
- EXPORT_SYMBOL(put_cmsg);
- EXPORT_SYMBOL(sock_kmalloc);
- EXPORT_SYMBOL(sock_kfree_s);
-+EXPORT_SYMBOL(sockfd_lookup);
-
- #ifdef CONFIG_FILTER
- EXPORT_SYMBOL(sk_run_filter);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff
deleted file mode 100644
index b31c57992f..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff
+++ /dev/null
@@ -1,30831 +0,0 @@
-diff -urN linux-2.4.18/CREDITS linux-2.4.18-mh9/CREDITS
---- linux-2.4.18/CREDITS Mon Feb 25 20:37:50 2002
-+++ linux-2.4.18-mh9/CREDITS Mon Aug 25 18:38:09 2003
-@@ -1317,6 +1317,14 @@
- S: Provo, Utah 84606-5607
- S: USA
-
-+N: Marcel Holtmann
-+E: marcel@holtmann.org
-+W: http://www.holtmann.org
-+D: Author and maintainer of the various Bluetooth HCI drivers
-+D: Author and maintainer of the CAPI message transport protocol driver
-+D: Various other Bluetooth related patches, cleanups and fixes
-+S: Germany
-+
- N: Rob W. W. Hooft
- E: hooft@EMBL-Heidelberg.DE
- D: Shared libs for graphics-tools and for the f2c compiler
-diff -urN linux-2.4.18/Documentation/Configure.help linux-2.4.18-mh9/Documentation/Configure.help
---- linux-2.4.18/Documentation/Configure.help Mon Feb 25 20:37:51 2002
-+++ linux-2.4.18-mh9/Documentation/Configure.help Mon Aug 25 18:38:10 2003
-@@ -2824,14 +2824,6 @@
-
- If unsure, say N.
-
--HCI EMU (virtual device) driver
--CONFIG_BLUEZ_HCIEMU
-- Bluetooth Virtual HCI device driver.
-- This driver is required if you want to use HCI Emulation software.
--
-- Say Y here to compile support for Virtual HCI devices into the
-- kernel or say M to compile it as module (hci_usb.o).
--
- # Choice: alphatype
- Alpha system type
- CONFIG_ALPHA_GENERIC
-@@ -11037,6 +11029,12 @@
-
- If unsure, say N.
-
-+Hotplug firmware loading support (EXPERIMENTAL)
-+CONFIG_FW_LOADER
-+ This option is provided for the case where no in-kernel-tree modules require
-+ hotplug firmware loading support, but a module built outside the kernel tree
-+ does.
-+
- Use PCI shared memory for NIC registers
- CONFIG_TULIP_MMIO
- Use PCI shared memory for the NIC registers, rather than going through
-@@ -19870,11 +19868,15 @@
- Bluetooth can be found at <http://www.bluetooth.com/>.
-
- Linux Bluetooth subsystem consist of several layers:
-- HCI Core (device and connection manager, scheduler)
-+ BlueZ Core (HCI device and connection manager, scheduler)
- HCI Device drivers (interface to the hardware)
- L2CAP Module (L2CAP protocol)
-+ SCO Module (SCO links)
-+ RFCOMM Module (RFCOMM protocol)
-+ BNEP Module (BNEP protocol)
-+ CMTP Module (CMTP protocol)
-
-- Say Y here to enable Linux Bluetooth support and to build HCI Core
-+ Say Y here to enable Linux Bluetooth support and to build BlueZ Core
- layer.
-
- To use Linux Bluetooth subsystem, you will need several user-space
-@@ -19882,7 +19884,7 @@
- Bluetooth kernel modules are provided in the BlueZ package.
- For more information, see <http://bluez.sourceforge.net/>.
-
-- If you want to compile HCI Core as module (hci.o) say M here.
-+ If you want to compile BlueZ Core as module (bluez.o) say M here.
-
- L2CAP protocol support
- CONFIG_BLUEZ_L2CAP
-@@ -19893,15 +19895,91 @@
- Say Y here to compile L2CAP support into the kernel or say M to
- compile it as module (l2cap.o).
-
-+SCO links support
-+CONFIG_BLUEZ_SCO
-+ SCO link provides voice transport over Bluetooth. SCO support is
-+ required for voice applications like Headset and Audio.
-+
-+ Say Y here to compile SCO support into the kernel or say M to
-+ compile it as module (sco.o).
-+
-+RFCOMM protocol support
-+CONFIG_BLUEZ_RFCOMM
-+ RFCOMM provides connection oriented stream transport. RFCOMM
-+ support is required for Dialup Networking, OBEX and other Bluetooth
-+ applications.
-+
-+ Say Y here to compile RFCOMM support into the kernel or say M to
-+ compile it as module (rfcomm.o).
-+
-+RFCOMM TTY emulation support
-+CONFIG_BLUEZ_RFCOMM_TTY
-+ This option enables TTY emulation support for RFCOMM channels.
-+
-+BNEP protocol support
-+CONFIG_BLUEZ_BNEP
-+ BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
-+ emulation layer on top of Bluetooth. BNEP is required for Bluetooth
-+ PAN (Personal Area Network).
-+
-+ To use BNEP, you will need user-space utilities provided in the
-+ BlueZ-PAN package.
-+ For more information, see <http://bluez.sourceforge.net>.
-+
-+ Say Y here to compile BNEP support into the kernel or say M to
-+ compile it as module (bnep.o).
-+
-+CMTP protocol support
-+CONFIG_BLUEZ_CMTP
-+ CMTP (CAPI Message Transport Protocol) is a transport layer
-+ for CAPI messages. CMTP is required for the Bluetooth Common
-+ ISDN Access Profile.
-+
-+ Say Y here to compile CMTP support into the kernel or say M to
-+ compile it as module (cmtp.o).
-+
-+BNEP multicast filter support
-+CONFIG_BLUEZ_BNEP_MC_FILTER
-+ This option enables the multicast filter support for BNEP.
-+
-+BNEP protocol filter support
-+CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ This option enables the protocol filter support for BNEP.
-+
- HCI UART driver
- CONFIG_BLUEZ_HCIUART
- Bluetooth HCI UART driver.
- This driver is required if you want to use Bluetooth devices with
-- serial port interface.
-+ serial port interface. You will also need this driver if you have
-+ UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
-+ adapter and BrainBoxes Bluetooth PC Card.
-
- Say Y here to compile support for Bluetooth UART devices into the
- kernel or say M to compile it as module (hci_uart.o).
-
-+HCI UART (H4) protocol support
-+CONFIG_BLUEZ_HCIUART_H4
-+ UART (H4) is serial protocol for communication between Bluetooth
-+ device and host. This protocol is required for most Bluetooth devices
-+ with UART interface, including PCMCIA and CF cards.
-+
-+ Say Y here to compile support for HCI UART (H4) protocol.
-+
-+HCI BCSP protocol support
-+CONFIG_BLUEZ_HCIUART_BCSP
-+ BCSP (BlueCore Serial Protocol) is serial protocol for communication
-+ between Bluetooth device and host. This protocol is required for non
-+ USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and
-+ CF cards.
-+
-+ Say Y here to compile support for HCI BCSP protocol.
-+
-+HCI BCSP transmit CRC with every BCSP packet
-+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ If you say Y here, a 16-bit CRC checksum will be transmitted along with
-+ every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
-+ This increases reliability, but slightly reduces efficiency.
-+
- HCI USB driver
- CONFIG_BLUEZ_HCIUSB
- Bluetooth HCI USB driver.
-@@ -19911,13 +19989,90 @@
- Say Y here to compile support for Bluetooth USB devices into the
- kernel or say M to compile it as module (hci_usb.o).
-
--HCI VHCI virtual HCI device driver
-+HCI USB SCO (voice) support
-+CONFIG_BLUEZ_USB_SCO
-+ This option enables the SCO support in the HCI USB driver. You need this
-+ to transmit voice data with your Bluetooth USB device. And your device
-+ must also support sending SCO data over the HCI layer, because some of
-+ them sends the SCO data to an internal PCM adapter.
-+
-+ Say Y here to compile support for HCI SCO data.
-+
-+HCI USB zero packet support
-+CONFIG_BLUEZ_USB_ZERO_PACKET
-+ This option is provided only as a work around for buggy Bluetooth USB
-+ devices. Do NOT enable it unless you know for sure that your device
-+ requires zero packets.
-+
-+ Most people should say N here.
-+
-+HCI VHCI Virtual HCI device driver
- CONFIG_BLUEZ_HCIVHCI
- Bluetooth Virtual HCI device driver.
- This driver is required if you want to use HCI Emulation software.
-
- Say Y here to compile support for virtual HCI devices into the
- kernel or say M to compile it as module (hci_vhci.o).
-+
-+HCI BFUSB device driver
-+CONFIG_BLUEZ_HCIBFUSB
-+ Bluetooth HCI BlueFRITZ! USB driver.
-+ This driver provides support for Bluetooth USB devices with AVM
-+ interface:
-+ AVM BlueFRITZ! USB
-+
-+ Say Y here to compile support for HCI BFUSB devices into the
-+ kernel or say M to compile it as module (bfusb.o).
-+
-+HCI DTL1 (PC Card) device driver
-+CONFIG_BLUEZ_HCIDTL1
-+ Bluetooth HCI DTL1 (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ Nokia DTL1 interface:
-+ Nokia Bluetooth Card
-+ Socket Bluetooth CF Card
-+
-+ Say Y here to compile support for HCI DTL1 devices into the
-+ kernel or say M to compile it as module (dtl1_cs.o).
-+
-+HCI BT3C (PC Card) device driver
-+CONFIG_BLUEZ_HCIBT3C
-+ Bluetooth HCI BT3C (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ 3Com BT3C interface:
-+ 3Com Bluetooth Card (3CRWB6096)
-+ HP Bluetooth Card
-+
-+ The HCI BT3C driver uses external firmware loader program provided in
-+ the BlueFW package. For more information, see <http://bluez.sf.net>.
-+
-+ Say Y here to compile support for HCI BT3C devices into the
-+ kernel or say M to compile it as module (bt3c_cs.o).
-+
-+HCI BlueCard (PC Card) device driver
-+CONFIG_BLUEZ_HCIBLUECARD
-+ Bluetooth HCI BlueCard (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ Anycom BlueCard interface:
-+ Anycom Bluetooth PC Card
-+ Anycom Bluetooth CF Card
-+
-+ Say Y here to compile support for HCI BlueCard devices into the
-+ kernel or say M to compile it as module (bluecard_cs.o).
-+
-+HCI UART (PC Card) device driver
-+CONFIG_BLUEZ_HCIBTUART
-+ Bluetooth HCI UART (PC Card) driver.
-+ This driver provides support for Bluetooth PCMCIA devices with
-+ an UART interface:
-+ Xircom CreditCard Bluetooth Adapter
-+ Xircom RealPort2 Bluetooth Adapter
-+ Sphinx PICO Card
-+ H-Soft blue+Card
-+ Cyber-blue Compact Flash Card
-+
-+ Say Y here to compile support for HCI UART devices into the
-+ kernel or say M to compile it as module (btuart_cs.o).
-
- # The following options are for Linux when running on the Hitachi
- # SuperH family of RISC microprocessors.
-diff -urN linux-2.4.18/Documentation/firmware_class/README linux-2.4.18-mh9/Documentation/firmware_class/README
---- linux-2.4.18/Documentation/firmware_class/README Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/Documentation/firmware_class/README Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,58 @@
-+
-+ request_firmware() hotplug interface:
-+ ------------------------------------
-+ Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+
-+ Why:
-+ ---
-+
-+ Today, the most extended way to use firmware in the Linux kernel is linking
-+ it statically in a header file. Which has political and technical issues:
-+
-+ 1) Some firmware is not legal to redistribute.
-+ 2) The firmware occupies memory permanently, even though it often is just
-+ used once.
-+ 3) Some people, like the Debian crowd, don't consider some firmware free
-+ enough and remove entire drivers (e.g.: keyspan).
-+
-+ about in-kernel persistence:
-+ ---------------------------
-+ Under some circumstances, as explained below, it would be interesting to keep
-+ firmware images in non-swappable kernel memory or even in the kernel image
-+ (probably within initramfs).
-+
-+ Note that this functionality has not been implemented.
-+
-+ - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
-+
-+ - If the device that needs the firmware is needed to access the
-+ filesystem. When upon some error the device has to be reset and the
-+ firmware reloaded, it won't be possible to get it from userspace.
-+ e.g.:
-+ - A diskless client with a network card that needs firmware.
-+ - The filesystem is stored in a disk behind an scsi device
-+ that needs firmware.
-+ - Replacing buggy DSDT/SSDT ACPI tables on boot.
-+ Note: this would require the persistent objects to be included
-+ within the kernel image, probably within initramfs.
-+
-+ And the same device can be needed to access the filesystem or not depending
-+ on the setup, so I think that the choice on what firmware to make
-+ persistent should be left to userspace.
-+
-+ - Why register_firmware()+__init can be useful:
-+ - For boot devices needing firmware.
-+ - To make the transition easier:
-+ The firmware can be declared __init and register_firmware()
-+ called on module_init. Then the firmware is warranted to be
-+ there even if "firmware hotplug userspace" is not there yet or
-+ it doesn't yet provide the needed firmware.
-+ Once the firmware is widely available in userspace, it can be
-+ removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
-+
-+ In either case, if firmware hotplug support is there, it can move the
-+ firmware out of kernel memory into the real filesystem for later
-+ usage.
-+
-+ Note: If persistence is implemented on top of initramfs,
-+ register_firmware() may not be appropriate.
-diff -urN linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c linux-2.4.18-mh9/Documentation/firmware_class/firmware_sample_driver.c
---- linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/Documentation/firmware_class/firmware_sample_driver.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,121 @@
-+/*
-+ * firmware_sample_driver.c -
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Sample code on how to use request_firmware() from drivers.
-+ *
-+ * Note that register_firmware() is currently useless.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/string.h>
-+
-+#include "linux/firmware.h"
-+
-+#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+char __init inkernel_firmware[] = "let's say that this is firmware\n";
-+#endif
-+
-+static char ghost_device[] = "ghost0";
-+
-+static void sample_firmware_load(char *firmware, int size)
-+{
-+ u8 buf[size+1];
-+ memcpy(buf, firmware, size);
-+ buf[size] = '\0';
-+ printk("firmware_sample_driver: firmware: %s\n", buf);
-+}
-+
-+static void sample_probe_default(void)
-+{
-+ /* uses the default method to get the firmware */
-+ const struct firmware *fw_entry;
-+ printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+ if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0)
-+ {
-+ printk(KERN_ERR
-+ "firmware_sample_driver: Firmware not available\n");
-+ return;
-+ }
-+
-+ sample_firmware_load(fw_entry->data, fw_entry->size);
-+
-+ release_firmware(fw_entry);
-+
-+ /* finish setting up the device */
-+}
-+static void sample_probe_specific(void)
-+{
-+ /* Uses some specific hotplug support to get the firmware from
-+ * userspace directly into the hardware, or via some sysfs file */
-+
-+ /* NOTE: This currently doesn't work */
-+
-+ printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+ if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0)
-+ {
-+ printk(KERN_ERR
-+ "firmware_sample_driver: Firmware load failed\n");
-+ return;
-+ }
-+
-+ /* request_firmware blocks until userspace finished, so at
-+ * this point the firmware should be already in the device */
-+
-+ /* finish setting up the device */
-+}
-+static void sample_probe_async_cont(const struct firmware *fw, void *context)
-+{
-+ if(!fw){
-+ printk(KERN_ERR
-+ "firmware_sample_driver: firmware load failed\n");
-+ return;
-+ }
-+
-+ printk("firmware_sample_driver: device pointer \"%s\"\n",
-+ (char *)context);
-+ sample_firmware_load(fw->data, fw->size);
-+}
-+static void sample_probe_async(void)
-+{
-+ /* Let's say that I can't sleep */
-+ int error;
-+ error = request_firmware_nowait (THIS_MODULE,
-+ "sample_driver_fw", ghost_device,
-+ "my device pointer",
-+ sample_probe_async_cont);
-+ if(error){
-+ printk(KERN_ERR
-+ "firmware_sample_driver:"
-+ " request_firmware_nowait failed\n");
-+ }
-+}
-+
-+static int sample_init(void)
-+{
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+ register_firmware("sample_driver_fw", inkernel_firmware,
-+ sizeof(inkernel_firmware));
-+#endif
-+ /* since there is no real hardware insertion I just call the
-+ * sample probe functions here */
-+ sample_probe_specific();
-+ sample_probe_default();
-+ sample_probe_async();
-+ return 0;
-+}
-+static void __exit sample_exit(void)
-+{
-+}
-+
-+module_init (sample_init);
-+module_exit (sample_exit);
-+
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/Documentation/firmware_class/hotplug-script linux-2.4.18-mh9/Documentation/firmware_class/hotplug-script
---- linux-2.4.18/Documentation/firmware_class/hotplug-script Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/Documentation/firmware_class/hotplug-script Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,16 @@
-+#!/bin/sh
-+
-+# Simple hotplug script sample:
-+#
-+# Both $DEVPATH and $FIRMWARE are already provided in the environment.
-+
-+HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
-+
-+echo 1 > /sysfs/$DEVPATH/loading
-+cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
-+echo 0 > /sysfs/$DEVPATH/loading
-+
-+# To cancel the load in case of error:
-+#
-+# echo -1 > /sysfs/$DEVPATH/loading
-+#
-diff -urN linux-2.4.18/MAINTAINERS linux-2.4.18-mh9/MAINTAINERS
---- linux-2.4.18/MAINTAINERS Mon Feb 25 20:37:52 2002
-+++ linux-2.4.18-mh9/MAINTAINERS Mon Aug 25 18:38:10 2003
-@@ -252,7 +252,73 @@
- L: linux-kernel@vger.kernel.org
- S: Maintained
-
--BLUETOOTH SUBSYSTEM (BlueZ)
-+BLUETOOTH SUBSYSTEM
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+W: http://bluez.sf.net
-+S: Maintained
-+
-+BLUETOOTH RFCOMM LAYER
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+W: http://bluez.sf.net
-+S: Maintained
-+
-+BLUETOOTH BNEP LAYER
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+W: http://bluez.sf.net
-+S: Maintained
-+
-+BLUETOOTH CMTP LAYER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH HCI USB DRIVER
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+W: http://bluez.sf.net
-+S: Maintained
-+
-+BLUETOOTH HCI UART DRIVER
-+P: Maxim Krasnyansky
-+M: maxk@qualcomm.com
-+W: http://bluez.sf.net
-+S: Maintained
-+
-+BLUETOOTH HCI BFUSB DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH HCI DTL1 DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH HCI BLUECARD DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH HCI BT3C DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH HCI BTUART DRIVER
-+P: Marcel Holtmann
-+M: marcel@holtmann.org
-+W: http://www.holtmann.org/linux/bluetooth/
-+S: Maintained
-+
-+BLUETOOTH HCI VHCI DRIVER
- P: Maxim Krasnyansky
- M: maxk@qualcomm.com
- W: http://bluez.sf.net
-diff -urN linux-2.4.18/arch/alpha/config.in linux-2.4.18-mh9/arch/alpha/config.in
---- linux-2.4.18/arch/alpha/config.in Wed Nov 21 00:49:31 2001
-+++ linux-2.4.18-mh9/arch/alpha/config.in Mon Aug 25 18:38:10 2003
-@@ -371,9 +371,7 @@
- source drivers/usb/Config.in
- source drivers/input/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/arm/config.in linux-2.4.18-mh9/arch/arm/config.in
---- linux-2.4.18/arch/arm/config.in Fri Nov 9 22:58:02 2001
-+++ linux-2.4.18-mh9/arch/arm/config.in Mon Aug 25 18:38:10 2003
-@@ -584,9 +584,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/i386/config.in linux-2.4.18-mh9/arch/i386/config.in
---- linux-2.4.18/arch/i386/config.in Mon Feb 25 20:37:52 2002
-+++ linux-2.4.18-mh9/arch/i386/config.in Mon Aug 25 18:38:10 2003
-@@ -407,9 +407,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/ppc/config.in linux-2.4.18-mh9/arch/ppc/config.in
---- linux-2.4.18/arch/ppc/config.in Mon Feb 25 20:37:55 2002
-+++ linux-2.4.18-mh9/arch/ppc/config.in Mon Aug 25 18:38:10 2003
-@@ -389,9 +389,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Kernel hacking'
-diff -urN linux-2.4.18/arch/sparc/config.in linux-2.4.18-mh9/arch/sparc/config.in
---- linux-2.4.18/arch/sparc/config.in Tue Jun 12 04:15:27 2001
-+++ linux-2.4.18-mh9/arch/sparc/config.in Mon Aug 25 18:38:10 2003
-@@ -251,9 +251,7 @@
-
- source fs/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Watchdog'
-diff -urN linux-2.4.18/arch/sparc64/config.in linux-2.4.18-mh9/arch/sparc64/config.in
---- linux-2.4.18/arch/sparc64/config.in Fri Dec 21 18:41:53 2001
-+++ linux-2.4.18-mh9/arch/sparc64/config.in Mon Aug 25 18:38:10 2003
-@@ -283,9 +283,7 @@
-
- source drivers/usb/Config.in
-
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
-
- mainmenu_option next_comment
- comment 'Watchdog'
-diff -urN linux-2.4.18/arch/sparc64/kernel/ioctl32.c linux-2.4.18-mh9/arch/sparc64/kernel/ioctl32.c
---- linux-2.4.18/arch/sparc64/kernel/ioctl32.c Mon Feb 25 20:37:56 2002
-+++ linux-2.4.18-mh9/arch/sparc64/kernel/ioctl32.c Mon Aug 25 18:38:10 2003
-@@ -92,6 +92,7 @@
-
- #include <net/bluetooth/bluetooth.h>
- #include <net/bluetooth/hci.h>
-+#include <net/bluetooth/rfcomm.h>
-
- #include <linux/usb.h>
- #include <linux/usbdevice_fs.h>
-@@ -3822,6 +3823,15 @@
- return err;
- }
-
-+/* Bluetooth ioctls */
-+#define HCIUARTSETPROTO _IOW('U', 200, int)
-+#define HCIUARTGETPROTO _IOR('U', 201, int)
-+
-+#define BNEPCONNADD _IOW('B', 200, int)
-+#define BNEPCONNDEL _IOW('B', 201, int)
-+#define BNEPGETCONNLIST _IOR('B', 210, int)
-+#define BNEPGETCONNINFO _IOR('B', 211, int)
-+
- struct mtd_oob_buf32 {
- u32 start;
- u32 length;
-@@ -3878,6 +3888,11 @@
- return ((0 == ret) ? 0 : -EFAULT);
- }
-
-+#define CMTPCONNADD _IOW('C', 200, int)
-+#define CMTPCONNDEL _IOW('C', 201, int)
-+#define CMTPGETCONNLIST _IOR('C', 210, int)
-+#define CMTPGETCONNINFO _IOR('C', 211, int)
-+
- struct ioctl_trans {
- unsigned int cmd;
- unsigned int handler;
-@@ -4540,6 +4555,21 @@
- COMPATIBLE_IOCTL(HCISETSCAN)
- COMPATIBLE_IOCTL(HCISETAUTH)
- COMPATIBLE_IOCTL(HCIINQUIRY)
-+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
-+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
-+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
-+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
-+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
-+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
-+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-+COMPATIBLE_IOCTL(BNEPCONNADD)
-+COMPATIBLE_IOCTL(BNEPCONNDEL)
-+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
-+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-+COMPATIBLE_IOCTL(CMTPCONNADD)
-+COMPATIBLE_IOCTL(CMTPCONNDEL)
-+COMPATIBLE_IOCTL(CMTPGETCONNLIST)
-+COMPATIBLE_IOCTL(CMTPGETCONNINFO)
- /* Misc. */
- COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */
- COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */
-diff -urN linux-2.4.18/drivers/bluetooth/Config.in linux-2.4.18-mh9/drivers/bluetooth/Config.in
---- linux-2.4.18/drivers/bluetooth/Config.in Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/drivers/bluetooth/Config.in Mon Aug 25 18:38:10 2003
-@@ -1,8 +1,34 @@
-+#
-+# Bluetooth HCI device drivers configuration
-+#
-+
- mainmenu_option next_comment
- comment 'Bluetooth device drivers'
-
- dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
-+if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
-+ bool ' SCO (voice) support' CONFIG_BLUEZ_USB_SCO
-+ bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET
-+fi
-+
- dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
--dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
-+if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
-+ bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
-+ bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
-+ dep_bool ' Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
-+fi
-+
-+dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB
-+
-+dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
-
- endmenu
-+
-diff -urN linux-2.4.18/drivers/bluetooth/Makefile linux-2.4.18-mh9/drivers/bluetooth/Makefile
---- linux-2.4.18/drivers/bluetooth/Makefile Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/drivers/bluetooth/Makefile Mon Aug 25 18:38:10 2003
-@@ -1,11 +1,27 @@
- #
--# Makefile for Bluetooth HCI device drivers.
-+# Makefile for the Linux Bluetooth HCI device drivers
- #
-
- O_TARGET := bluetooth.o
-
-+list-multi := hci_uart.o
-+
- obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o
--obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
- obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o
-
-+obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
-+uart-y := hci_ldisc.o
-+uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o
-+uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o
-+
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o
-+
-+obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o
-+
- include $(TOPDIR)/Rules.make
-+
-+hci_uart.o: $(uart-y)
-+ $(LD) -r -o $@ $(uart-y)
-diff -urN linux-2.4.18/drivers/bluetooth/Makefile.lib linux-2.4.18-mh9/drivers/bluetooth/Makefile.lib
---- linux-2.4.18/drivers/bluetooth/Makefile.lib Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/Makefile.lib Mon Aug 25 18:38:10 2003
-@@ -0,0 +1 @@
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
-diff -urN linux-2.4.18/drivers/bluetooth/bfusb.c linux-2.4.18-mh9/drivers/bluetooth/bfusb.c
---- linux-2.4.18/drivers/bluetooth/bfusb.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/bfusb.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,781 @@
-+/*
-+ *
-+ * AVM BlueFRITZ! USB driver
-+ *
-+ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/skbuff.h>
-+
-+#include <linux/firmware.h>
-+#include <linux/usb.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.1"
-+
-+static struct usb_device_id bfusb_table[] = {
-+ /* AVM BlueFRITZ! USB */
-+ { USB_DEVICE(0x057c, 0x2200) },
-+
-+ { } /* Terminating entry */
-+};
-+
-+MODULE_DEVICE_TABLE(usb, bfusb_table);
-+
-+
-+#define BFUSB_MAX_BLOCK_SIZE 256
-+
-+#define BFUSB_BLOCK_TIMEOUT (HZ * 3)
-+
-+#define BFUSB_TX_PROCESS 1
-+#define BFUSB_TX_WAKEUP 2
-+
-+#define BFUSB_MAX_BULK_TX 1
-+#define BFUSB_MAX_BULK_RX 1
-+
-+struct bfusb {
-+ struct hci_dev hdev;
-+
-+ unsigned long state;
-+
-+ struct usb_device *udev;
-+
-+ unsigned int bulk_in_ep;
-+ unsigned int bulk_out_ep;
-+ unsigned int bulk_pkt_size;
-+
-+ rwlock_t lock;
-+
-+ struct sk_buff_head transmit_q;
-+
-+ struct sk_buff *reassembly;
-+
-+ atomic_t pending_tx;
-+ struct sk_buff_head pending_q;
-+ struct sk_buff_head completed_q;
-+};
-+
-+struct bfusb_scb {
-+ struct urb *urb;
-+};
-+
-+static void bfusb_tx_complete(struct urb *urb);
-+static void bfusb_rx_complete(struct urb *urb);
-+
-+static struct urb *bfusb_get_completed(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+ struct urb *urb = NULL;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ skb = skb_dequeue(&bfusb->completed_q);
-+ if (skb) {
-+ urb = ((struct bfusb_scb *) skb->cb)->urb;
-+ kfree_skb(skb);
-+ }
-+
-+ return urb;
-+}
-+
-+static inline void bfusb_unlink_urbs(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+ struct urb *urb;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ while ((skb = skb_dequeue(&bfusb->pending_q))) {
-+ urb = ((struct bfusb_scb *) skb->cb)->urb;
-+ usb_unlink_urb(urb);
-+ skb_queue_tail(&bfusb->completed_q, skb);
-+ }
-+
-+ while ((urb = bfusb_get_completed(bfusb)))
-+ usb_free_urb(urb);
-+}
-+
-+
-+static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
-+{
-+ struct bfusb_scb *scb = (void *) skb->cb;
-+ struct urb *urb = bfusb_get_completed(bfusb);
-+ int err, pipe;
-+
-+ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
-+
-+ if (!urb && !(urb = usb_alloc_urb(0)))
-+ return -ENOMEM;
-+
-+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len,
-+ bfusb_tx_complete, skb);
-+
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ scb->urb = urb;
-+
-+ skb_queue_tail(&bfusb->pending_q, skb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk tx submit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ skb_unlink(skb);
-+ usb_free_urb(urb);
-+ } else
-+ atomic_inc(&bfusb->pending_tx);
-+
-+ return err;
-+}
-+
-+static void bfusb_tx_wakeup(struct bfusb *bfusb)
-+{
-+ struct sk_buff *skb;
-+
-+ BT_DBG("bfusb %p", bfusb);
-+
-+ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
-+ set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+ return;
-+ }
-+
-+ do {
-+ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+
-+ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
-+ (skb = skb_dequeue(&bfusb->transmit_q))) {
-+ if (bfusb_send_bulk(bfusb, skb) < 0) {
-+ skb_queue_head(&bfusb->transmit_q, skb);
-+ break;
-+ }
-+ }
-+
-+ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
-+
-+ clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
-+}
-+
-+static void bfusb_tx_complete(struct urb *urb)
-+{
-+ struct sk_buff *skb = (struct sk_buff *) urb->context;
-+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+
-+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+ atomic_dec(&bfusb->pending_tx);
-+
-+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+ return;
-+
-+ if (!urb->status)
-+ bfusb->hdev.stat.byte_tx += skb->len;
-+ else
-+ bfusb->hdev.stat.err_tx++;
-+
-+ read_lock(&bfusb->lock);
-+
-+ skb_unlink(skb);
-+ skb_queue_tail(&bfusb->completed_q, skb);
-+
-+ bfusb_tx_wakeup(bfusb);
-+
-+ read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
-+{
-+ struct bfusb_scb *scb;
-+ struct sk_buff *skb;
-+ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
-+
-+ BT_DBG("bfusb %p urb %p", bfusb, urb);
-+
-+ if (!urb && !(urb = usb_alloc_urb(0)))
-+ return -ENOMEM;
-+
-+ if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
-+ usb_free_urb(urb);
-+ return -ENOMEM;
-+ }
-+
-+ skb->dev = (void *) bfusb;
-+
-+ scb = (struct bfusb_scb *) skb->cb;
-+ scb->urb = urb;
-+
-+ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
-+
-+ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size,
-+ bfusb_rx_complete, skb);
-+
-+ urb->transfer_flags = USB_QUEUE_BULK;
-+
-+ skb_queue_tail(&bfusb->pending_q, skb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk rx submit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ skb_unlink(skb);
-+ kfree_skb(skb);
-+ usb_free_urb(urb);
-+ }
-+
-+ return err;
-+}
-+
-+static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
-+{
-+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
-+
-+ if (hdr & 0x10) {
-+ BT_ERR("%s error in block", bfusb->hdev.name);
-+ if (bfusb->reassembly)
-+ kfree_skb(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ return -EIO;
-+ }
-+
-+ if (hdr & 0x04) {
-+ struct sk_buff *skb;
-+ unsigned char pkt_type;
-+ int pkt_len = 0;
-+
-+ if (bfusb->reassembly) {
-+ BT_ERR("%s unexpected start block", bfusb->hdev.name);
-+ kfree_skb(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ }
-+
-+ if (len < 1) {
-+ BT_ERR("%s no packet type found", bfusb->hdev.name);
-+ return -EPROTO;
-+ }
-+
-+ pkt_type = *data++; len--;
-+
-+ switch (pkt_type) {
-+ case HCI_EVENT_PKT:
-+ if (len >= HCI_EVENT_HDR_SIZE) {
-+ hci_event_hdr *hdr = (hci_event_hdr *) data;
-+ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
-+ } else {
-+ BT_ERR("%s event block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ if (len >= HCI_ACL_HDR_SIZE) {
-+ hci_acl_hdr *hdr = (hci_acl_hdr *) data;
-+ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
-+ } else {
-+ BT_ERR("%s data block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ if (len >= HCI_SCO_HDR_SIZE) {
-+ hci_sco_hdr *hdr = (hci_sco_hdr *) data;
-+ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
-+ } else {
-+ BT_ERR("%s audio block is too short", bfusb->hdev.name);
-+ return -EILSEQ;
-+ }
-+ break;
-+ }
-+
-+ skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s no memory for the packet", bfusb->hdev.name);
-+ return -ENOMEM;
-+ }
-+
-+ skb->dev = (void *) &bfusb->hdev;
-+ skb->pkt_type = pkt_type;
-+
-+ bfusb->reassembly = skb;
-+ } else {
-+ if (!bfusb->reassembly) {
-+ BT_ERR("%s unexpected continuation block", bfusb->hdev.name);
-+ return -EIO;
-+ }
-+ }
-+
-+ if (len > 0)
-+ memcpy(skb_put(bfusb->reassembly, len), data, len);
-+
-+ if (hdr & 0x08) {
-+ hci_recv_frame(bfusb->reassembly);
-+ bfusb->reassembly = NULL;
-+ }
-+
-+ return 0;
-+}
-+
-+static void bfusb_rx_complete(struct urb *urb)
-+{
-+ struct sk_buff *skb = (struct sk_buff *) urb->context;
-+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+ unsigned char *buf = urb->transfer_buffer;
-+ int count = urb->actual_length;
-+ int err, hdr, len;
-+
-+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+ return;
-+
-+ read_lock(&bfusb->lock);
-+
-+ if (urb->status || !count)
-+ goto resubmit;
-+
-+ bfusb->hdev.stat.byte_rx += count;
-+
-+ skb_put(skb, count);
-+
-+ while (count) {
-+ hdr = buf[0] | (buf[1] << 8);
-+
-+ if (hdr & 0x4000) {
-+ len = 0;
-+ count -= 2;
-+ buf += 2;
-+ } else {
-+ len = (buf[2] == 0) ? 256 : buf[2];
-+ count -= 3;
-+ buf += 3;
-+ }
-+
-+ if (count < len) {
-+ BT_ERR("%s block extends over URB buffer ranges",
-+ bfusb->hdev.name);
-+ }
-+
-+ if ((hdr & 0xe1) == 0xc1)
-+ bfusb_recv_block(bfusb, hdr, buf, len);
-+
-+ count -= len;
-+ buf += len;
-+ }
-+
-+ skb_unlink(skb);
-+ kfree_skb(skb);
-+
-+ bfusb_rx_submit(bfusb, urb);
-+
-+ read_unlock(&bfusb->lock);
-+
-+ return;
-+
-+resubmit:
-+ urb->dev = bfusb->udev;
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk resubmit failed urb %p err %d",
-+ bfusb->hdev.name, urb, err);
-+ }
-+
-+ read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_open(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+ unsigned long flags;
-+ int i, err;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ write_lock_irqsave(&bfusb->lock, flags);
-+
-+ err = bfusb_rx_submit(bfusb, NULL);
-+ if (!err) {
-+ for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
-+ bfusb_rx_submit(bfusb, NULL);
-+ } else {
-+ clear_bit(HCI_RUNNING, &hdev->flags);
-+ MOD_DEC_USE_COUNT;
-+ }
-+
-+ write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+ return err;
-+}
-+
-+static int bfusb_flush(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ skb_queue_purge(&bfusb->transmit_q);
-+
-+ return 0;
-+}
-+
-+static int bfusb_close(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+ unsigned long flags;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ write_lock_irqsave(&bfusb->lock, flags);
-+
-+ bfusb_unlink_urbs(bfusb);
-+ bfusb_flush(hdev);
-+
-+ write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+static int bfusb_send_frame(struct sk_buff *skb)
-+{
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-+ struct bfusb *bfusb;
-+ struct sk_buff *nskb;
-+ unsigned char buf[3];
-+ int sent = 0, size, count;
-+
-+ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
-+
-+ if (!hdev) {
-+ BT_ERR("Frame for unknown HCI device (hdev=NULL)");
-+ return -ENODEV;
-+ }
-+
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-+
-+ bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+
-+ count = skb->len;
-+
-+ /* Max HCI frame size seems to be 1511 + 1 */
-+ if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new packet");
-+ return -ENOMEM;
-+ }
-+
-+ nskb->dev = (void *) bfusb;
-+
-+ while (count) {
-+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
-+
-+ buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
-+ buf[1] = 0x00;
-+ buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
-+
-+ memcpy(skb_put(nskb, 3), buf, 3);
-+ memcpy(skb_put(nskb, size), skb->data + sent, size);
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ /* Don't send frame with multiple size of bulk max packet */
-+ if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
-+ buf[0] = 0xdd;
-+ buf[1] = 0x00;
-+ memcpy(skb_put(nskb, 2), buf, 2);
-+ }
-+
-+ read_lock(&bfusb->lock);
-+
-+ skb_queue_tail(&bfusb->transmit_q, nskb);
-+ bfusb_tx_wakeup(bfusb);
-+
-+ read_unlock(&bfusb->lock);
-+
-+ kfree_skb(skb);
-+
-+ return 0;
-+}
-+
-+static void bfusb_destruct(struct hci_dev *hdev)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+ kfree(bfusb);
-+}
-+
-+static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
-+{
-+ unsigned char *buf;
-+ int err, pipe, len, size, sent = 0;
-+
-+ BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count);
-+
-+ BT_INFO("BlueFRITZ! USB loading firmware");
-+
-+ if (usb_set_configuration(bfusb->udev, 1) < 0) {
-+ BT_ERR("Can't change to loading configuration");
-+ return -EBUSY;
-+ }
-+
-+ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
-+ if (!buf) {
-+ BT_ERR("Can't allocate memory chunk for firmware");
-+ return -ENOMEM;
-+ }
-+
-+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+ while (count) {
-+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
-+
-+ memcpy(buf, firmware + sent, size);
-+
-+ err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
-+ &len, BFUSB_BLOCK_TIMEOUT);
-+
-+ if (err || (len != size)) {
-+ BT_ERR("Error in firmware loading");
-+ goto error;
-+ }
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
-+ &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
-+ BT_ERR("Error in null packet request");
-+ goto error;
-+ }
-+
-+ if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) {
-+ BT_ERR("Can't change to running configuration");
-+ goto error;
-+ }
-+
-+ BT_INFO("BlueFRITZ! USB device ready");
-+
-+ kfree(buf);
-+ return 0;
-+
-+error:
-+ kfree(buf);
-+
-+ pipe = usb_sndctrlpipe(bfusb->udev, 0);
-+
-+ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-+ 0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT);
-+
-+ return err;
-+}
-+
-+static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+{
-+ const struct firmware *firmware;
-+ char device[16];
-+ struct usb_interface *iface;
-+ struct usb_interface_descriptor *iface_desc;
-+ struct usb_endpoint_descriptor *bulk_out_ep;
-+ struct usb_endpoint_descriptor *bulk_in_ep;
-+ struct hci_dev *hdev;
-+ struct bfusb *bfusb;
-+
-+ BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id);
-+
-+ /* Check number of endpoints */
-+ iface = &udev->actconfig->interface[0];
-+ iface_desc = &iface->altsetting[0];
-+
-+ if (iface_desc->bNumEndpoints < 2)
-+ return NULL;
-+
-+ bulk_out_ep = &iface_desc->endpoint[0];
-+ bulk_in_ep = &iface_desc->endpoint[1];
-+
-+ if (!bulk_out_ep || !bulk_in_ep) {
-+ BT_ERR("Bulk endpoints not found");
-+ goto done;
-+ }
-+
-+ /* Initialize control structure and load firmware */
-+ if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) {
-+ BT_ERR("Can't allocate memory for control structure");
-+ goto done;
-+ }
-+
-+ memset(bfusb, 0, sizeof(struct bfusb));
-+
-+ bfusb->udev = udev;
-+ bfusb->bulk_in_ep = bulk_in_ep->bEndpointAddress;
-+ bfusb->bulk_out_ep = bulk_out_ep->bEndpointAddress;
-+ bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize;
-+
-+ bfusb->lock = RW_LOCK_UNLOCKED;
-+
-+ bfusb->reassembly = NULL;
-+
-+ skb_queue_head_init(&bfusb->transmit_q);
-+ skb_queue_head_init(&bfusb->pending_q);
-+ skb_queue_head_init(&bfusb->completed_q);
-+
-+ snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum);
-+
-+ if (request_firmware(&firmware, "bfubase.frm", device) < 0) {
-+ BT_ERR("Firmware request failed");
-+ goto error;
-+ }
-+
-+ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
-+ BT_ERR("Firmware loading failed");
-+ goto release;
-+ }
-+
-+ release_firmware(firmware);
-+
-+ /* Initialize and register HCI device */
-+ hdev = &bfusb->hdev;
-+
-+ hdev->type = HCI_USB;
-+ hdev->driver_data = bfusb;
-+
-+ hdev->open = bfusb_open;
-+ hdev->close = bfusb_close;
-+ hdev->flush = bfusb_flush;
-+ hdev->send = bfusb_send_frame;
-+ hdev->destruct = bfusb_destruct;
-+ hdev->ioctl = bfusb_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ BT_ERR("Can't register HCI device");
-+ goto error;
-+ }
-+
-+ return bfusb;
-+
-+release:
-+ release_firmware(firmware);
-+
-+error:
-+ kfree(bfusb);
-+
-+done:
-+ return NULL;
-+}
-+
-+static void bfusb_disconnect(struct usb_device *udev, void *ptr)
-+{
-+ struct bfusb *bfusb = (struct bfusb *) ptr;
-+ struct hci_dev *hdev = &bfusb->hdev;
-+
-+ BT_DBG("udev %p ptr %p", udev, ptr);
-+
-+ if (!hdev)
-+ return;
-+
-+ bfusb_close(hdev);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ BT_ERR("Can't unregister HCI device %s", hdev->name);
-+}
-+
-+static struct usb_driver bfusb_driver = {
-+ name: "bfusb",
-+ probe: bfusb_probe,
-+ disconnect: bfusb_disconnect,
-+ id_table: bfusb_table,
-+};
-+
-+static int __init bfusb_init(void)
-+{
-+ int err;
-+
-+ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ if ((err = usb_register(&bfusb_driver)) < 0)
-+ BT_ERR("Failed to register BlueFRITZ! USB driver");
-+
-+ return err;
-+}
-+
-+static void __exit bfusb_cleanup(void)
-+{
-+ usb_deregister(&bfusb_driver);
-+}
-+
-+module_init(bfusb_init);
-+module_exit(bfusb_cleanup);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/bluecard_cs.c linux-2.4.18-mh9/drivers/bluetooth/bluecard_cs.c
---- linux-2.4.18/drivers/bluetooth/bluecard_cs.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/bluecard_cs.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,1113 @@
-+/*
-+ *
-+ * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+#include <linux/skbuff.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0x86bc;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct bluecard_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+ struct timer_list timer; /* For LED control */
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+
-+ unsigned char ctrl_reg;
-+ unsigned long hw_state; /* Status of the hardware and LED control */
-+} bluecard_info_t;
-+
-+
-+void bluecard_config(dev_link_t *link);
-+void bluecard_release(u_long arg);
-+int bluecard_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "bluecard_cs";
-+
-+dev_link_t *bluecard_attach(void);
-+void bluecard_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Default baud rate: 57600, 115200, 230400 or 460800 */
-+#define DEFAULT_BAUD_RATE 230400
-+
-+
-+/* Hardware states */
-+#define CARD_READY 1
-+#define CARD_HAS_PCCARD_ID 4
-+#define CARD_HAS_POWER_LED 5
-+#define CARD_HAS_ACTIVITY_LED 6
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */
-+#define XMIT_BUF_ONE_READY 6
-+#define XMIT_BUF_TWO_READY 7
-+#define XMIT_SENDING_READY 8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER 1
-+#define RECV_WAIT_ACL_HEADER 2
-+#define RECV_WAIT_SCO_HEADER 3
-+#define RECV_WAIT_DATA 4
-+
-+/* Special packet types */
-+#define PKT_BAUD_RATE_57600 0x80
-+#define PKT_BAUD_RATE_115200 0x81
-+#define PKT_BAUD_RATE_230400 0x82
-+#define PKT_BAUD_RATE_460800 0x83
-+
-+
-+/* These are the register offsets */
-+#define REG_COMMAND 0x20
-+#define REG_INTERRUPT 0x21
-+#define REG_CONTROL 0x22
-+#define REG_RX_CONTROL 0x24
-+#define REG_CARD_RESET 0x30
-+#define REG_LED_CTRL 0x30
-+
-+/* REG_COMMAND */
-+#define REG_COMMAND_TX_BUF_ONE 0x01
-+#define REG_COMMAND_TX_BUF_TWO 0x02
-+#define REG_COMMAND_RX_BUF_ONE 0x04
-+#define REG_COMMAND_RX_BUF_TWO 0x08
-+#define REG_COMMAND_RX_WIN_ONE 0x00
-+#define REG_COMMAND_RX_WIN_TWO 0x10
-+
-+/* REG_CONTROL */
-+#define REG_CONTROL_BAUD_RATE_57600 0x00
-+#define REG_CONTROL_BAUD_RATE_115200 0x01
-+#define REG_CONTROL_BAUD_RATE_230400 0x02
-+#define REG_CONTROL_BAUD_RATE_460800 0x03
-+#define REG_CONTROL_RTS 0x04
-+#define REG_CONTROL_BT_ON 0x08
-+#define REG_CONTROL_BT_RESET 0x10
-+#define REG_CONTROL_BT_RES_PU 0x20
-+#define REG_CONTROL_INTERRUPT 0x40
-+#define REG_CONTROL_CARD_RESET 0x80
-+
-+/* REG_RX_CONTROL */
-+#define RTS_LEVEL_SHIFT_BITS 0x02
-+
-+
-+
-+/* ======================== LED handling routines ======================== */
-+
-+
-+void bluecard_activity_led_timeout(u_long arg)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)arg;
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
-+ /* Disable activity LED */
-+ outb(0x08 | 0x20, iobase + 0x30);
-+ } else {
-+ /* Disable power LED */
-+ outb(0x00, iobase + 0x30);
-+ }
-+}
-+
-+
-+static void bluecard_enable_activity_led(bluecard_info_t *info)
-+{
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
-+ /* Enable activity LED */
-+ outb(0x10 | 0x40, iobase + 0x30);
-+
-+ /* Stop the LED after HZ/4 */
-+ mod_timer(&(info->timer), jiffies + HZ / 4);
-+ } else {
-+ /* Enable power LED */
-+ outb(0x08 | 0x20, iobase + 0x30);
-+
-+ /* Stop the LED after HZ/2 */
-+ mod_timer(&(info->timer), jiffies + HZ / 2);
-+ }
-+}
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
-+{
-+ int i, actual;
-+
-+ actual = (len > 15) ? 15 : len;
-+
-+ outb_p(actual, iobase + offset);
-+
-+ for (i = 0; i < actual; i++)
-+ outb_p(buf[i], iobase + offset + i + 1);
-+
-+ return actual;
-+}
-+
-+
-+static void bluecard_write_wakeup(bluecard_info_t *info)
-+{
-+ if (!info) {
-+ printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
-+ return;
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register unsigned int offset;
-+ register unsigned char command;
-+ register unsigned long ready_bit;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ return;
-+
-+ if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
-+ if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
-+ break;
-+ offset = 0x10;
-+ command = REG_COMMAND_TX_BUF_TWO;
-+ ready_bit = XMIT_BUF_TWO_READY;
-+ } else {
-+ if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
-+ break;
-+ offset = 0x00;
-+ command = REG_COMMAND_TX_BUF_ONE;
-+ ready_bit = XMIT_BUF_ONE_READY;
-+ }
-+
-+ if (!(skb = skb_dequeue(&(info->txq))))
-+ break;
-+
-+ if (skb->pkt_type & 0x80) {
-+ /* Disable RTS */
-+ info->ctrl_reg |= REG_CONTROL_RTS;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+ }
-+
-+ /* Activate LED */
-+ bluecard_enable_activity_led(info);
-+
-+ /* Send frame */
-+ len = bluecard_write(iobase, offset, skb->data, skb->len);
-+
-+ /* Tell the FPGA to send the data */
-+ outb_p(command, iobase + REG_COMMAND);
-+
-+ /* Mark the buffer as dirty */
-+ clear_bit(ready_bit, &(info->tx_state));
-+
-+ if (skb->pkt_type & 0x80) {
-+
-+ wait_queue_head_t wait;
-+ unsigned char baud_reg;
-+
-+ switch (skb->pkt_type) {
-+ case PKT_BAUD_RATE_460800:
-+ baud_reg = REG_CONTROL_BAUD_RATE_460800;
-+ break;
-+ case PKT_BAUD_RATE_230400:
-+ baud_reg = REG_CONTROL_BAUD_RATE_230400;
-+ break;
-+ case PKT_BAUD_RATE_115200:
-+ baud_reg = REG_CONTROL_BAUD_RATE_115200;
-+ break;
-+ case PKT_BAUD_RATE_57600:
-+ /* Fall through... */
-+ default:
-+ baud_reg = REG_CONTROL_BAUD_RATE_57600;
-+ break;
-+ }
-+
-+ /* Wait until the command reaches the baseband */
-+ init_waitqueue_head(&wait);
-+ interruptible_sleep_on_timeout(&wait, HZ / 10);
-+
-+ /* Set baud on baseband */
-+ info->ctrl_reg &= ~0x03;
-+ info->ctrl_reg |= baud_reg;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Enable RTS */
-+ info->ctrl_reg &= ~REG_CONTROL_RTS;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Wait before the next HCI packet can be send */
-+ interruptible_sleep_on_timeout(&wait, HZ);
-+
-+ }
-+
-+ if (len == skb->len) {
-+ kfree_skb(skb);
-+ } else {
-+ skb_pull(skb, len);
-+ skb_queue_head(&(info->txq), skb);
-+ }
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ /* Change buffer */
-+ change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
-+
-+ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
-+{
-+ int i, n, len;
-+
-+ outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
-+
-+ len = inb(iobase + offset);
-+ n = 0;
-+ i = 1;
-+
-+ while (n < len) {
-+
-+ if (i == 16) {
-+ outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
-+ i = 0;
-+ }
-+
-+ buf[n] = inb(iobase + offset + i);
-+
-+ n++;
-+ i++;
-+
-+ }
-+
-+ return len;
-+}
-+
-+
-+static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
-+{
-+ unsigned int iobase;
-+ unsigned char buf[31];
-+ int i, len;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
-+ bluecard_enable_activity_led(info);
-+
-+ len = bluecard_read(iobase, offset, buf, sizeof(buf));
-+
-+ for (i = 0; i < len; i++) {
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL) {
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
-+ return;
-+ }
-+ }
-+
-+ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type = buf[i];
-+
-+ switch (info->rx_skb->pkt_type) {
-+
-+ case 0x00:
-+ /* init packet */
-+ if (offset != 0x00) {
-+ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
-+ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
-+ set_bit(XMIT_SENDING_READY, &(info->tx_state));
-+ bluecard_write_wakeup(info);
-+ }
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ case HCI_EVENT_PKT:
-+ info->rx_state = RECV_WAIT_EVENT_HEADER;
-+ info->rx_count = HCI_EVENT_HDR_SIZE;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ info->rx_state = RECV_WAIT_ACL_HEADER;
-+ info->rx_count = HCI_ACL_HDR_SIZE;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ info->rx_state = RECV_WAIT_SCO_HEADER;
-+ info->rx_count = HCI_SCO_HDR_SIZE;
-+ break;
-+
-+ default:
-+ /* unknown packet */
-+ printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ info->hdev.stat.err_rx++;
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ } else {
-+
-+ *skb_put(info->rx_skb, 1) = buf[i];
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ int dlen;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+
-+ switch (info->rx_state) {
-+
-+ case RECV_WAIT_EVENT_HEADER:
-+ eh = (hci_event_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = eh->plen;
-+ break;
-+
-+ case RECV_WAIT_ACL_HEADER:
-+ ah = (hci_acl_hdr *)(info->rx_skb->data);
-+ dlen = __le16_to_cpu(ah->dlen);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = dlen;
-+ break;
-+
-+ case RECV_WAIT_SCO_HEADER:
-+ sh = (hci_sco_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = sh->dlen;
-+ break;
-+
-+ case RECV_WAIT_DATA:
-+ hci_recv_frame(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+
-+ }
-+
-+ info->hdev.stat.byte_rx += len;
-+}
-+
-+
-+void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ bluecard_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ unsigned char reg;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ if (!test_bit(CARD_READY, &(info->hw_state)))
-+ return;
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ /* Disable interrupt */
-+ info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ reg = inb(iobase + REG_INTERRUPT);
-+
-+ if ((reg != 0x00) && (reg != 0xff)) {
-+
-+ if (reg & 0x04) {
-+ bluecard_receive(info, 0x00);
-+ outb(0x04, iobase + REG_INTERRUPT);
-+ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
-+ }
-+
-+ if (reg & 0x08) {
-+ bluecard_receive(info, 0x10);
-+ outb(0x08, iobase + REG_INTERRUPT);
-+ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
-+ }
-+
-+ if (reg & 0x01) {
-+ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
-+ outb(0x01, iobase + REG_INTERRUPT);
-+ bluecard_write_wakeup(info);
-+ }
-+
-+ if (reg & 0x02) {
-+ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
-+ outb(0x02, iobase + REG_INTERRUPT);
-+ bluecard_write_wakeup(info);
-+ }
-+
-+ }
-+
-+ /* Enable interrupt */
-+ info->ctrl_reg |= REG_CONTROL_INTERRUPT;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+/* ======================== Device specific HCI commands ======================== */
-+
-+
-+static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+ struct sk_buff *skb;
-+
-+ /* Ericsson baud rate command */
-+ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
-+
-+ if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
-+ return -1;
-+ }
-+
-+ switch (baud) {
-+ case 460800:
-+ cmd[4] = 0x00;
-+ skb->pkt_type = PKT_BAUD_RATE_460800;
-+ break;
-+ case 230400:
-+ cmd[4] = 0x01;
-+ skb->pkt_type = PKT_BAUD_RATE_230400;
-+ break;
-+ case 115200:
-+ cmd[4] = 0x02;
-+ skb->pkt_type = PKT_BAUD_RATE_115200;
-+ break;
-+ case 57600:
-+ /* Fall through... */
-+ default:
-+ cmd[4] = 0x03;
-+ skb->pkt_type = PKT_BAUD_RATE_57600;
-+ break;
-+ }
-+
-+ memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
-+
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ bluecard_write_wakeup(info);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int bluecard_hci_flush(struct hci_dev *hdev)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int bluecard_hci_open(struct hci_dev *hdev)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
-+
-+ if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ /* Enable LED */
-+ outb(0x08 | 0x20, iobase + 0x30);
-+
-+ return 0;
-+}
-+
-+
-+static int bluecard_hci_close(struct hci_dev *hdev)
-+{
-+ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+ unsigned int iobase = info->link.io.BasePort1;
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ bluecard_hci_flush(hdev);
-+
-+ /* Disable LED */
-+ outb(0x00, iobase + 0x30);
-+
-+ return 0;
-+}
-+
-+
-+static int bluecard_hci_send_frame(struct sk_buff *skb)
-+{
-+ bluecard_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (bluecard_info_t *)(hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ bluecard_write_wakeup(info);
-+
-+ return 0;
-+}
-+
-+
-+static void bluecard_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int bluecard_open(bluecard_info_t *info)
-+{
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev;
-+ unsigned char id;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ init_timer(&(info->timer));
-+ info->timer.function = &bluecard_activity_led_timeout;
-+ info->timer.data = (u_long)info;
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ info->rx_skb = NULL;
-+
-+ id = inb(iobase + 0x30);
-+
-+ if ((id & 0x0f) == 0x02)
-+ set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
-+
-+ if (id & 0x10)
-+ set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
-+
-+ if (id & 0x20)
-+ set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
-+
-+ /* Reset card */
-+ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Turn FPGA off */
-+ outb(0x80, iobase + 0x30);
-+
-+ /* Wait some time */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ / 100);
-+
-+ /* Turn FPGA on */
-+ outb(0x00, iobase + 0x30);
-+
-+ /* Activate card */
-+ info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Enable interrupt */
-+ outb(0xff, iobase + REG_INTERRUPT);
-+ info->ctrl_reg |= REG_CONTROL_INTERRUPT;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Start the RX buffers */
-+ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
-+ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
-+
-+ /* Signal that the hardware is ready */
-+ set_bit(CARD_READY, &(info->hw_state));
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ /* Control the point at which RTS is enabled */
-+ outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout((HZ * 5) / 4); // or set it to 3/2
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = bluecard_hci_open;
-+ hdev->close = bluecard_hci_close;
-+ hdev->flush = bluecard_hci_flush;
-+ hdev->send = bluecard_hci_send_frame;
-+ hdev->destruct = bluecard_hci_destruct;
-+ hdev->ioctl = bluecard_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int bluecard_close(bluecard_info_t *info)
-+{
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ bluecard_hci_close(hdev);
-+
-+ clear_bit(CARD_READY, &(info->hw_state));
-+
-+ /* Reset card */
-+ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
-+ outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+ /* Turn FPGA off */
-+ outb(0x80, iobase + 0x30);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *bluecard_attach(void)
-+{
-+ bluecard_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &bluecard_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = bluecard_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &bluecard_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ bluecard_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void bluecard_detach(dev_link_t *link)
-+{
-+ bluecard_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+ if (link->state & DEV_CONFIG)
-+ bluecard_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void bluecard_config(dev_link_t *link)
-+{
-+ client_handle_t handle = link->handle;
-+ bluecard_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ config_info_t config;
-+ int i, n, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ link->conf.ConfigIndex = 0x20;
-+ link->io.NumPorts1 = 64;
-+ link->io.IOAddrLines = 6;
-+
-+ for (n = 0; n < 0x400; n += 0x40) {
-+ link->io.BasePort1 = n ^ 0x300;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ break;
-+ }
-+
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (bluecard_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ bluecard_release((u_long)link);
-+}
-+
-+
-+void bluecard_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ bluecard_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ bluecard_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int bluecard_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ bluecard_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ bluecard_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ bluecard_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_bluecard_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_bluecard_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ bluecard_detach(dev_list);
-+}
-+
-+
-+module_init(init_bluecard_cs);
-+module_exit(exit_bluecard_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/bt3c_cs.c linux-2.4.18-mh9/drivers/bluetooth/bt3c_cs.c
---- linux-2.4.18/drivers/bluetooth/bt3c_cs.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/bt3c_cs.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,946 @@
-+/*
-+ *
-+ * Driver for the 3Com Bluetooth PCMCIA card
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ * Jose Orlando Pereira <jop@di.uminho.pt>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/kernel.h>
-+#include <linux/kmod.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/unistd.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
-+MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct bt3c_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+} bt3c_info_t;
-+
-+
-+void bt3c_config(dev_link_t *link);
-+void bt3c_release(u_long arg);
-+int bt3c_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "bt3c_cs";
-+
-+dev_link_t *bt3c_attach(void);
-+void bt3c_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_WAITING 8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER 1
-+#define RECV_WAIT_ACL_HEADER 2
-+#define RECV_WAIT_SCO_HEADER 3
-+#define RECV_WAIT_DATA 4
-+
-+
-+
-+/* ======================== Special I/O functions ======================== */
-+
-+
-+#define DATA_L 0
-+#define DATA_H 1
-+#define ADDR_L 2
-+#define ADDR_H 3
-+#define CONTROL 4
-+
-+
-+inline void bt3c_address(unsigned int iobase, unsigned short addr)
-+{
-+ outb(addr & 0xff, iobase + ADDR_L);
-+ outb((addr >> 8) & 0xff, iobase + ADDR_H);
-+}
-+
-+
-+inline void bt3c_put(unsigned int iobase, unsigned short value)
-+{
-+ outb(value & 0xff, iobase + DATA_L);
-+ outb((value >> 8) & 0xff, iobase + DATA_H);
-+}
-+
-+
-+inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
-+{
-+ bt3c_address(iobase, addr);
-+ bt3c_put(iobase, value);
-+}
-+
-+
-+inline unsigned short bt3c_get(unsigned int iobase)
-+{
-+ unsigned short value = inb(iobase + DATA_L);
-+
-+ value |= inb(iobase + DATA_H) << 8;
-+
-+ return value;
-+}
-+
-+
-+inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
-+{
-+ bt3c_address(iobase, addr);
-+
-+ return bt3c_get(iobase);
-+}
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+ int actual = 0;
-+
-+ bt3c_address(iobase, 0x7080);
-+
-+ /* Fill FIFO with current frame */
-+ while (actual < len) {
-+ /* Transmit next byte */
-+ bt3c_put(iobase, buf[actual]);
-+ actual++;
-+ }
-+
-+ bt3c_io_write(iobase, 0x7005, actual);
-+
-+ return actual;
-+}
-+
-+
-+static void bt3c_write_wakeup(bt3c_info_t *info, int from)
-+{
-+ unsigned long flags;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
-+ return;
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ break;
-+
-+
-+ if (!(skb = skb_dequeue(&(info->txq)))) {
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+ break;
-+ }
-+
-+ /* Send frame */
-+ len = bt3c_write(iobase, 256, skb->data, skb->len);
-+
-+ if (len != skb->len) {
-+ printk(KERN_WARNING "bt3c_cs: very strange\n");
-+ }
-+
-+ kfree_skb(skb);
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ } while (0);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+}
-+
-+
-+static void bt3c_receive(bt3c_info_t *info)
-+{
-+ unsigned int iobase;
-+ int size = 0, avail;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ avail = bt3c_read(iobase, 0x7006);
-+ //printk("bt3c_cs: receiving %d bytes\n", avail);
-+
-+ bt3c_address(iobase, 0x7480);
-+ while (size < avail) {
-+ size++;
-+ info->hdev.stat.byte_rx++;
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL) {
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
-+ return;
-+ }
-+ }
-+
-+
-+ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type = inb(iobase + DATA_L);
-+ inb(iobase + DATA_H);
-+ //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
-+
-+ switch (info->rx_skb->pkt_type) {
-+
-+ case HCI_EVENT_PKT:
-+ info->rx_state = RECV_WAIT_EVENT_HEADER;
-+ info->rx_count = HCI_EVENT_HDR_SIZE;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ info->rx_state = RECV_WAIT_ACL_HEADER;
-+ info->rx_count = HCI_ACL_HDR_SIZE;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ info->rx_state = RECV_WAIT_SCO_HEADER;
-+ info->rx_count = HCI_SCO_HDR_SIZE;
-+ break;
-+
-+ default:
-+ /* Unknown packet */
-+ printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ info->hdev.stat.err_rx++;
-+ clear_bit(HCI_RUNNING, &(info->hdev.flags));
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ } else {
-+
-+ __u8 x = inb(iobase + DATA_L);
-+
-+ *skb_put(info->rx_skb, 1) = x;
-+ inb(iobase + DATA_H);
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ int dlen;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+
-+ switch (info->rx_state) {
-+
-+ case RECV_WAIT_EVENT_HEADER:
-+ eh = (hci_event_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = eh->plen;
-+ break;
-+
-+ case RECV_WAIT_ACL_HEADER:
-+ ah = (hci_acl_hdr *)(info->rx_skb->data);
-+ dlen = __le16_to_cpu(ah->dlen);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = dlen;
-+ break;
-+
-+ case RECV_WAIT_SCO_HEADER:
-+ sh = (hci_sco_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = sh->dlen;
-+ break;
-+
-+ case RECV_WAIT_DATA:
-+ hci_recv_frame(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+ bt3c_io_write(iobase, 0x7006, 0x0000);
-+}
-+
-+
-+void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ bt3c_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ int iir;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ iir = inb(iobase + CONTROL);
-+ if (iir & 0x80) {
-+ int stat = bt3c_read(iobase, 0x7001);
-+
-+ if ((stat & 0xff) == 0x7f) {
-+ printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
-+ } else if ((stat & 0xff) != 0xff) {
-+ if (stat & 0x0020) {
-+ int stat = bt3c_read(iobase, 0x7002) & 0x10;
-+ printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
-+ }
-+ if (stat & 0x0001)
-+ bt3c_receive(info);
-+ if (stat & 0x0002) {
-+ //printk("bt3c_cs: ACK %04x\n", stat);
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+ bt3c_write_wakeup(info, 1);
-+ }
-+
-+ bt3c_io_write(iobase, 0x7001, 0x0000);
-+
-+ outb(iir, iobase + CONTROL);
-+ }
-+ }
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int bt3c_hci_flush(struct hci_dev *hdev)
-+{
-+ bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int bt3c_hci_open(struct hci_dev *hdev)
-+{
-+ set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+ return 0;
-+}
-+
-+
-+static int bt3c_hci_close(struct hci_dev *hdev)
-+{
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ bt3c_hci_flush(hdev);
-+
-+ return 0;
-+}
-+
-+
-+static int bt3c_hci_send_frame(struct sk_buff *skb)
-+{
-+ bt3c_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (bt3c_info_t *) (hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ bt3c_write_wakeup(info, 0);
-+
-+ return 0;
-+}
-+
-+
-+static void bt3c_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== User mode firmware loader ======================== */
-+
-+
-+#define FW_LOADER "/sbin/bluefw"
-+static int errno;
-+
-+
-+static int bt3c_fw_loader_exec(void *dev)
-+{
-+ char *argv[] = { FW_LOADER, "pccard", dev, NULL };
-+ char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-+ int err;
-+
-+ err = exec_usermodehelper(FW_LOADER, argv, envp);
-+ if (err)
-+ printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
-+
-+ return err;
-+}
-+
-+
-+static int bt3c_firmware_load(bt3c_info_t *info)
-+{
-+ sigset_t tmpsig;
-+ char dev[16];
-+ pid_t pid;
-+ int result;
-+
-+ /* Check if root fs is mounted */
-+ if (!current->fs->root) {
-+ printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
-+ return -EPERM;
-+ }
-+
-+ sprintf(dev, "%04x", info->link.io.BasePort1);
-+
-+ pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
-+ if (pid < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
-+ return pid;
-+ }
-+
-+ /* Block signals, everything but SIGKILL/SIGSTOP */
-+ spin_lock_irq(&current->sigmask_lock);
-+ tmpsig = current->blocked;
-+ siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-+ recalc_sigpending(current);
-+ spin_unlock_irq(&current->sigmask_lock);
-+
-+ result = waitpid(pid, NULL, __WCLONE);
-+
-+ /* Allow signals again */
-+ spin_lock_irq(&current->sigmask_lock);
-+ current->blocked = tmpsig;
-+ recalc_sigpending(current);
-+ spin_unlock_irq(&current->sigmask_lock);
-+
-+ if (result != pid) {
-+ printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
-+ return -result;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int bt3c_open(bt3c_info_t *info)
-+{
-+ struct hci_dev *hdev;
-+ int err;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ info->rx_skb = NULL;
-+
-+ /* Load firmware */
-+
-+ if ((err = bt3c_firmware_load(info)) < 0)
-+ return err;
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ);
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = bt3c_hci_open;
-+ hdev->close = bt3c_hci_close;
-+ hdev->flush = bt3c_hci_flush;
-+ hdev->send = bt3c_hci_send_frame;
-+ hdev->destruct = bt3c_hci_destruct;
-+ hdev->ioctl = bt3c_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int bt3c_close(bt3c_info_t *info)
-+{
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ bt3c_hci_close(hdev);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *bt3c_attach(void)
-+{
-+ bt3c_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &bt3c_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = bt3c_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &bt3c_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ bt3c_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void bt3c_detach(dev_link_t *link)
-+{
-+ bt3c_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+
-+ if (link->state & DEV_CONFIG)
-+ bt3c_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void bt3c_config(dev_link_t *link)
-+{
-+ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-+ client_handle_t handle = link->handle;
-+ bt3c_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
-+ int i, j, try, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ /* First pass: look for a config entry that looks normal. */
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+ /* Two tries: without IO aliases, then with aliases */
-+ for (try = 0; try < 2; try++) {
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if (i != CS_SUCCESS)
-+ goto next_entry;
-+ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-+ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-+ link->conf.ConfigIndex = cf->index;
-+ link->io.BasePort1 = cf->io.win[0].base;
-+ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+next_entry:
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+ }
-+
-+ /* Second pass: try to find an entry that isn't picky about
-+ its base address, then try to grab any standard serial port
-+ address, and finally try to get any free port. */
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-+ link->conf.ConfigIndex = cf->index;
-+ for (j = 0; j < 5; j++) {
-+ link->io.BasePort1 = base[j];
-+ link->io.IOAddrLines = base[j] ? 16 : 3;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+ }
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+
-+found_port:
-+ if (i != CS_SUCCESS) {
-+ printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n");
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (bt3c_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ bt3c_release((u_long)link);
-+}
-+
-+
-+void bt3c_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ bt3c_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ bt3c_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int bt3c_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ bt3c_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ bt3c_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ bt3c_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_bt3c_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_bt3c_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ bt3c_detach(dev_list);
-+}
-+
-+
-+module_init(init_bt3c_cs);
-+module_exit(exit_bt3c_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/btuart_cs.c linux-2.4.18-mh9/drivers/bluetooth/btuart_cs.c
---- linux-2.4.18/drivers/bluetooth/btuart_cs.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/btuart_cs.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,906 @@
-+/*
-+ *
-+ * Driver for Bluetooth PCMCIA cards with HCI UART interface
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct btuart_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+} btuart_info_t;
-+
-+
-+void btuart_config(dev_link_t *link);
-+void btuart_release(u_long arg);
-+int btuart_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "btuart_cs";
-+
-+dev_link_t *btuart_attach(void);
-+void btuart_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Maximum baud rate */
-+#define SPEED_MAX 115200
-+
-+/* Default baud rate: 57600, 115200, 230400 or 460800 */
-+#define DEFAULT_BAUD_RATE 115200
-+
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_WAITING 8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER 1
-+#define RECV_WAIT_ACL_HEADER 2
-+#define RECV_WAIT_SCO_HEADER 3
-+#define RECV_WAIT_DATA 4
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+ int actual = 0;
-+
-+ /* Tx FIFO should be empty */
-+ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-+ return 0;
-+
-+ /* Fill FIFO with current frame */
-+ while ((fifo_size-- > 0) && (actual < len)) {
-+ /* Transmit next byte */
-+ outb(buf[actual], iobase + UART_TX);
-+ actual++;
-+ }
-+
-+ return actual;
-+}
-+
-+
-+static void btuart_write_wakeup(btuart_info_t *info)
-+{
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ return;
-+
-+ if (!(skb = skb_dequeue(&(info->txq))))
-+ break;
-+
-+ /* Send frame */
-+ len = btuart_write(iobase, 16, skb->data, skb->len);
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (len == skb->len) {
-+ kfree_skb(skb);
-+ } else {
-+ skb_pull(skb, len);
-+ skb_queue_head(&(info->txq), skb);
-+ }
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static void btuart_receive(btuart_info_t *info)
-+{
-+ unsigned int iobase;
-+ int boguscount = 0;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ do {
-+ info->hdev.stat.byte_rx++;
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL) {
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
-+ return;
-+ }
-+ }
-+
-+ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type = inb(iobase + UART_RX);
-+
-+ switch (info->rx_skb->pkt_type) {
-+
-+ case HCI_EVENT_PKT:
-+ info->rx_state = RECV_WAIT_EVENT_HEADER;
-+ info->rx_count = HCI_EVENT_HDR_SIZE;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ info->rx_state = RECV_WAIT_ACL_HEADER;
-+ info->rx_count = HCI_ACL_HDR_SIZE;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ info->rx_state = RECV_WAIT_SCO_HEADER;
-+ info->rx_count = HCI_SCO_HDR_SIZE;
-+ break;
-+
-+ default:
-+ /* Unknown packet */
-+ printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ info->hdev.stat.err_rx++;
-+ clear_bit(HCI_RUNNING, &(info->hdev.flags));
-+
-+ kfree_skb(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ } else {
-+
-+ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ int dlen;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+
-+
-+ switch (info->rx_state) {
-+
-+ case RECV_WAIT_EVENT_HEADER:
-+ eh = (hci_event_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = eh->plen;
-+ break;
-+
-+ case RECV_WAIT_ACL_HEADER:
-+ ah = (hci_acl_hdr *)(info->rx_skb->data);
-+ dlen = __le16_to_cpu(ah->dlen);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = dlen;
-+ break;
-+
-+ case RECV_WAIT_SCO_HEADER:
-+ sh = (hci_sco_hdr *)(info->rx_skb->data);
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = sh->dlen;
-+ break;
-+
-+ case RECV_WAIT_DATA:
-+ hci_recv_frame(info->rx_skb);
-+ info->rx_skb = NULL;
-+ break;
-+
-+ }
-+
-+ }
-+
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 16)
-+ break;
-+
-+ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-+}
-+
-+
-+void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ btuart_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ int boguscount = 0;
-+ int iir, lsr;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+ while (iir) {
-+
-+ /* Clear interrupt */
-+ lsr = inb(iobase + UART_LSR);
-+
-+ switch (iir) {
-+ case UART_IIR_RLSI:
-+ printk(KERN_NOTICE "btuart_cs: RLSI\n");
-+ break;
-+ case UART_IIR_RDI:
-+ /* Receive interrupt */
-+ btuart_receive(info);
-+ break;
-+ case UART_IIR_THRI:
-+ if (lsr & UART_LSR_THRE) {
-+ /* Transmitter ready for data */
-+ btuart_write_wakeup(info);
-+ }
-+ break;
-+ default:
-+ printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
-+ break;
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 100)
-+ break;
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+
-+ }
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
-+{
-+ unsigned long flags;
-+ unsigned int iobase;
-+ int fcr; /* FIFO control reg */
-+ int lcr; /* Line control reg */
-+ int divisor;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ divisor = SPEED_MAX / speed;
-+
-+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
-+
-+ /*
-+ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
-+ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
-+ * about this timeout since it will always be fast enough.
-+ */
-+
-+ if (speed < 38400)
-+ fcr |= UART_FCR_TRIGGER_1;
-+ else
-+ fcr |= UART_FCR_TRIGGER_14;
-+
-+ /* Bluetooth cards use 8N1 */
-+ lcr = UART_LCR_WLEN8;
-+
-+ outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
-+ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
-+ outb(divisor >> 8, iobase + UART_DLM);
-+ outb(lcr, iobase + UART_LCR); /* Set 8N1 */
-+ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
-+
-+ /* Turn on interrups */
-+ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int btuart_hci_flush(struct hci_dev *hdev)
-+{
-+ btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int btuart_hci_open(struct hci_dev *hdev)
-+{
-+ set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+ return 0;
-+}
-+
-+
-+static int btuart_hci_close(struct hci_dev *hdev)
-+{
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ btuart_hci_flush(hdev);
-+
-+ return 0;
-+}
-+
-+
-+static int btuart_hci_send_frame(struct sk_buff *skb)
-+{
-+ btuart_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (btuart_info_t *)(hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+ };
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+ skb_queue_tail(&(info->txq), skb);
-+
-+ btuart_write_wakeup(info);
-+
-+ return 0;
-+}
-+
-+
-+static void btuart_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int btuart_open(btuart_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_PACKET_TYPE;
-+ info->rx_count = 0;
-+ info->rx_skb = NULL;
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ /* Initialize UART */
-+ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
-+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-+
-+ /* Turn on interrupts */
-+ // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ btuart_change_speed(info, DEFAULT_BAUD_RATE);
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ);
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = btuart_hci_open;
-+ hdev->close = btuart_hci_close;
-+ hdev->flush = btuart_hci_flush;
-+ hdev->send = btuart_hci_send_frame;
-+ hdev->destruct = btuart_hci_destruct;
-+ hdev->ioctl = btuart_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int btuart_close(btuart_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ btuart_hci_close(hdev);
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *btuart_attach(void)
-+{
-+ btuart_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &btuart_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = btuart_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &btuart_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ btuart_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void btuart_detach(dev_link_t *link)
-+{
-+ btuart_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+ if (link->state & DEV_CONFIG)
-+ btuart_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void btuart_config(dev_link_t *link)
-+{
-+ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-+ client_handle_t handle = link->handle;
-+ btuart_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
-+ int i, j, try, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ /* First pass: look for a config entry that looks normal. */
-+ tuple.TupleData = (cisdata_t *) buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+ /* Two tries: without IO aliases, then with aliases */
-+ for (try = 0; try < 2; try++) {
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if (i != CS_SUCCESS)
-+ goto next_entry;
-+ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-+ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-+ link->conf.ConfigIndex = cf->index;
-+ link->io.BasePort1 = cf->io.win[0].base;
-+ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+next_entry:
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+ }
-+
-+ /* Second pass: try to find an entry that isn't picky about
-+ its base address, then try to grab any standard serial port
-+ address, and finally try to get any free port. */
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
-+ && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-+ link->conf.ConfigIndex = cf->index;
-+ for (j = 0; j < 5; j++) {
-+ link->io.BasePort1 = base[j];
-+ link->io.IOAddrLines = base[j] ? 16 : 3;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ goto found_port;
-+ }
-+ }
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+
-+found_port:
-+ if (i != CS_SUCCESS) {
-+ printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (btuart_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ btuart_release((u_long) link);
-+}
-+
-+
-+void btuart_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ btuart_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ btuart_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int btuart_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ btuart_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ btuart_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ btuart_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_btuart_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_btuart_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ btuart_detach(dev_list);
-+}
-+
-+
-+module_init(init_btuart_cs);
-+module_exit(exit_btuart_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/dtl1_cs.c linux-2.4.18-mh9/drivers/bluetooth/dtl1_cs.c
---- linux-2.4.18/drivers/bluetooth/dtl1_cs.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/dtl1_cs.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,858 @@
-+/*
-+ *
-+ * A driver for Nokia Connectivity Card DTL-1 devices
-+ *
-+ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation;
-+ *
-+ * Software distributed under the License is distributed on an "AS
-+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ * implied. See the License for the specific language governing
-+ * rights and limitations under the License.
-+ *
-+ * The initial developer of the original code is David A. Hinds
-+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
-+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct dtl1_info_t {
-+ dev_link_t link;
-+ dev_node_t node;
-+
-+ struct hci_dev hdev;
-+
-+ spinlock_t lock; /* For serializing operations */
-+
-+ unsigned long flowmask; /* HCI flow mask */
-+ int ri_latch;
-+
-+ struct sk_buff_head txq;
-+ unsigned long tx_state;
-+
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+} dtl1_info_t;
-+
-+
-+void dtl1_config(dev_link_t *link);
-+void dtl1_release(u_long arg);
-+int dtl1_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "dtl1_cs";
-+
-+dev_link_t *dtl1_attach(void);
-+void dtl1_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Transmit states */
-+#define XMIT_SENDING 1
-+#define XMIT_WAKEUP 2
-+#define XMIT_WAITING 8
-+
-+/* Receiver States */
-+#define RECV_WAIT_NSH 0
-+#define RECV_WAIT_DATA 1
-+
-+
-+typedef struct {
-+ u8 type;
-+ u8 zero;
-+ u16 len;
-+} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */
-+
-+#define NSHL 4 /* Nokia Specific Header Length */
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+ int actual = 0;
-+
-+ /* Tx FIFO should be empty */
-+ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-+ return 0;
-+
-+ /* Fill FIFO with current frame */
-+ while ((fifo_size-- > 0) && (actual < len)) {
-+ /* Transmit next byte */
-+ outb(buf[actual], iobase + UART_TX);
-+ actual++;
-+ }
-+
-+ return actual;
-+}
-+
-+
-+static void dtl1_write_wakeup(dtl1_info_t *info)
-+{
-+ if (!info) {
-+ printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
-+ return;
-+ }
-+
-+ if (test_bit(XMIT_WAITING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+ set_bit(XMIT_WAKEUP, &(info->tx_state));
-+ return;
-+ }
-+
-+ do {
-+ register unsigned int iobase = info->link.io.BasePort1;
-+ register struct sk_buff *skb;
-+ register int len;
-+
-+ clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+ if (!(info->link.state & DEV_PRESENT))
-+ return;
-+
-+ if (!(skb = skb_dequeue(&(info->txq))))
-+ break;
-+
-+ /* Send frame */
-+ len = dtl1_write(iobase, 32, skb->data, skb->len);
-+
-+ if (len == skb->len) {
-+ set_bit(XMIT_WAITING, &(info->tx_state));
-+ kfree_skb(skb);
-+ } else {
-+ skb_pull(skb, len);
-+ skb_queue_head(&(info->txq), skb);
-+ }
-+
-+ info->hdev.stat.byte_tx += len;
-+
-+ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+ clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
-+{
-+ u8 flowmask = *(u8 *)skb->data;
-+ int i;
-+
-+ printk(KERN_INFO "dtl1_cs: Nokia control data = ");
-+ for (i = 0; i < skb->len; i++) {
-+ printk("%02x ", skb->data[i]);
-+ }
-+ printk("\n");
-+
-+ /* transition to active state */
-+ if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
-+ clear_bit(XMIT_WAITING, &(info->tx_state));
-+ dtl1_write_wakeup(info);
-+ }
-+
-+ info->flowmask = flowmask;
-+
-+ kfree_skb(skb);
-+}
-+
-+
-+static void dtl1_receive(dtl1_info_t *info)
-+{
-+ unsigned int iobase;
-+ nsh_t *nsh;
-+ int boguscount = 0;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ do {
-+ info->hdev.stat.byte_rx++;
-+
-+ /* Allocate packet */
-+ if (info->rx_skb == NULL)
-+ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+ printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
-+ info->rx_state = RECV_WAIT_NSH;
-+ info->rx_count = NSHL;
-+ return;
-+ }
-+
-+ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-+ nsh = (nsh_t *)info->rx_skb->data;
-+
-+ info->rx_count--;
-+
-+ if (info->rx_count == 0) {
-+
-+ switch (info->rx_state) {
-+ case RECV_WAIT_NSH:
-+ info->rx_state = RECV_WAIT_DATA;
-+ info->rx_count = nsh->len + (nsh->len & 0x0001);
-+ break;
-+ case RECV_WAIT_DATA:
-+ info->rx_skb->pkt_type = nsh->type;
-+
-+ /* remove PAD byte if it exists */
-+ if (nsh->len & 0x0001) {
-+ info->rx_skb->tail--;
-+ info->rx_skb->len--;
-+ }
-+
-+ /* remove NSH */
-+ skb_pull(info->rx_skb, NSHL);
-+
-+ switch (info->rx_skb->pkt_type) {
-+ case 0x80:
-+ /* control data for the Nokia Card */
-+ dtl1_control(info, info->rx_skb);
-+ break;
-+ case 0x82:
-+ case 0x83:
-+ case 0x84:
-+ /* send frame to the HCI layer */
-+ info->rx_skb->dev = (void *)&(info->hdev);
-+ info->rx_skb->pkt_type &= 0x0f;
-+ hci_recv_frame(info->rx_skb);
-+ break;
-+ default:
-+ /* unknown packet */
-+ printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+ kfree_skb(info->rx_skb);
-+ break;
-+ }
-+
-+ info->rx_state = RECV_WAIT_NSH;
-+ info->rx_count = NSHL;
-+ info->rx_skb = NULL;
-+ break;
-+ }
-+
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 32)
-+ break;
-+
-+ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-+}
-+
-+
-+void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+ dtl1_info_t *info = dev_inst;
-+ unsigned int iobase;
-+ unsigned char msr;
-+ int boguscount = 0;
-+ int iir, lsr;
-+
-+ if (!info) {
-+ printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
-+ return;
-+ }
-+
-+ iobase = info->link.io.BasePort1;
-+
-+ spin_lock(&(info->lock));
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+ while (iir) {
-+
-+ /* Clear interrupt */
-+ lsr = inb(iobase + UART_LSR);
-+
-+ switch (iir) {
-+ case UART_IIR_RLSI:
-+ printk(KERN_NOTICE "dtl1_cs: RLSI\n");
-+ break;
-+ case UART_IIR_RDI:
-+ /* Receive interrupt */
-+ dtl1_receive(info);
-+ break;
-+ case UART_IIR_THRI:
-+ if (lsr & UART_LSR_THRE) {
-+ /* Transmitter ready for data */
-+ dtl1_write_wakeup(info);
-+ }
-+ break;
-+ default:
-+ printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
-+ break;
-+ }
-+
-+ /* Make sure we don't stay here to long */
-+ if (boguscount++ > 100)
-+ break;
-+
-+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+
-+ }
-+
-+ msr = inb(iobase + UART_MSR);
-+
-+ if (info->ri_latch ^ (msr & UART_MSR_RI)) {
-+ info->ri_latch = msr & UART_MSR_RI;
-+ clear_bit(XMIT_WAITING, &(info->tx_state));
-+ dtl1_write_wakeup(info);
-+ }
-+
-+ spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int dtl1_hci_open(struct hci_dev *hdev)
-+{
-+ set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+ return 0;
-+}
-+
-+
-+static int dtl1_hci_flush(struct hci_dev *hdev)
-+{
-+ dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
-+
-+ /* Drop TX queue */
-+ skb_queue_purge(&(info->txq));
-+
-+ return 0;
-+}
-+
-+
-+static int dtl1_hci_close(struct hci_dev *hdev)
-+{
-+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+ return 0;
-+
-+ dtl1_hci_flush(hdev);
-+
-+ return 0;
-+}
-+
-+
-+static int dtl1_hci_send_frame(struct sk_buff *skb)
-+{
-+ dtl1_info_t *info;
-+ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+ struct sk_buff *s;
-+ nsh_t nsh;
-+
-+ if (!hdev) {
-+ printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
-+ return -ENODEV;
-+ }
-+
-+ info = (dtl1_info_t *)(hdev->driver_data);
-+
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ nsh.type = 0x81;
-+ break;
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ nsh.type = 0x82;
-+ break;
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ nsh.type = 0x83;
-+ break;
-+ };
-+
-+ nsh.zero = 0;
-+ nsh.len = skb->len;
-+
-+ s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
-+ skb_reserve(s, NSHL);
-+ memcpy(skb_put(s, skb->len), skb->data, skb->len);
-+ if (skb->len & 0x0001)
-+ *skb_put(s, 1) = 0; /* PAD */
-+
-+ /* Prepend skb with Nokia frame header and queue */
-+ memcpy(skb_push(s, NSHL), &nsh, NSHL);
-+ skb_queue_tail(&(info->txq), s);
-+
-+ dtl1_write_wakeup(info);
-+
-+ kfree_skb(skb);
-+
-+ return 0;
-+}
-+
-+
-+static void dtl1_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int dtl1_open(dtl1_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev;
-+
-+ spin_lock_init(&(info->lock));
-+
-+ skb_queue_head_init(&(info->txq));
-+
-+ info->rx_state = RECV_WAIT_NSH;
-+ info->rx_count = NSHL;
-+ info->rx_skb = NULL;
-+
-+ set_bit(XMIT_WAITING, &(info->tx_state));
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ /* Initialize UART */
-+ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
-+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-+
-+ info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
-+
-+ /* Turn on interrupts */
-+ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ /* Timeout before it is safe to send the first HCI packet */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(HZ * 2);
-+
-+
-+ /* Initialize and register HCI device */
-+
-+ hdev = &(info->hdev);
-+
-+ hdev->type = HCI_PCCARD;
-+ hdev->driver_data = info;
-+
-+ hdev->open = dtl1_hci_open;
-+ hdev->close = dtl1_hci_close;
-+ hdev->flush = dtl1_hci_flush;
-+ hdev->send = dtl1_hci_send_frame;
-+ hdev->destruct = dtl1_hci_destruct;
-+ hdev->ioctl = dtl1_hci_ioctl;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int dtl1_close(dtl1_info_t *info)
-+{
-+ unsigned long flags;
-+ unsigned int iobase = info->link.io.BasePort1;
-+ struct hci_dev *hdev = &(info->hdev);
-+
-+ dtl1_hci_close(hdev);
-+
-+ spin_lock_irqsave(&(info->lock), flags);
-+
-+ /* Reset UART */
-+ outb(0, iobase + UART_MCR);
-+
-+ /* Turn off interrupts */
-+ outb(0, iobase + UART_IER);
-+
-+ spin_unlock_irqrestore(&(info->lock), flags);
-+
-+ if (hci_unregister_dev(hdev) < 0)
-+ printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+ error_info_t err = { func, ret };
-+
-+ CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *dtl1_attach(void)
-+{
-+ dtl1_info_t *info;
-+ client_reg_t client_reg;
-+ dev_link_t *link;
-+ int i, ret;
-+
-+ /* Create new info device */
-+ info = kmalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return NULL;
-+ memset(info, 0, sizeof(*info));
-+
-+ link = &info->link;
-+ link->priv = info;
-+
-+ link->release.function = &dtl1_release;
-+ link->release.data = (u_long)link;
-+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+ link->io.NumPorts1 = 8;
-+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+ if (irq_list[0] == -1)
-+ link->irq.IRQInfo2 = irq_mask;
-+ else
-+ for (i = 0; i < 4; i++)
-+ link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+ link->irq.Handler = dtl1_interrupt;
-+ link->irq.Instance = info;
-+
-+ link->conf.Attributes = CONF_ENABLE_IRQ;
-+ link->conf.Vcc = 50;
-+ link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+ /* Register with Card Services */
-+ link->next = dev_list;
-+ dev_list = link;
-+ client_reg.dev_info = &dev_info;
-+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+ client_reg.EventMask =
-+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+ client_reg.event_handler = &dtl1_event;
-+ client_reg.Version = 0x0210;
-+ client_reg.event_callback_args.client_data = link;
-+
-+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+ if (ret != CS_SUCCESS) {
-+ cs_error(link->handle, RegisterClient, ret);
-+ dtl1_detach(link);
-+ return NULL;
-+ }
-+
-+ return link;
-+}
-+
-+
-+void dtl1_detach(dev_link_t *link)
-+{
-+ dtl1_info_t *info = link->priv;
-+ dev_link_t **linkp;
-+ int ret;
-+
-+ /* Locate device structure */
-+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+ if (*linkp == link)
-+ break;
-+
-+ if (*linkp == NULL)
-+ return;
-+
-+ del_timer(&link->release);
-+ if (link->state & DEV_CONFIG)
-+ dtl1_release((u_long)link);
-+
-+ if (link->handle) {
-+ ret = CardServices(DeregisterClient, link->handle);
-+ if (ret != CS_SUCCESS)
-+ cs_error(link->handle, DeregisterClient, ret);
-+ }
-+
-+ /* Unlink device structure, free bits */
-+ *linkp = link->next;
-+
-+ kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+ int i;
-+
-+ i = CardServices(fn, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return CS_NO_MORE_ITEMS;
-+
-+ i = CardServices(GetTupleData, handle, tuple);
-+ if (i != CS_SUCCESS)
-+ return i;
-+
-+ return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void dtl1_config(dev_link_t *link)
-+{
-+ client_handle_t handle = link->handle;
-+ dtl1_info_t *info = link->priv;
-+ tuple_t tuple;
-+ u_short buf[256];
-+ cisparse_t parse;
-+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
-+ int i, last_ret, last_fn;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+
-+ /* Get configuration register information */
-+ tuple.DesiredTuple = CISTPL_CONFIG;
-+ last_ret = first_tuple(handle, &tuple, &parse);
-+ if (last_ret != CS_SUCCESS) {
-+ last_fn = ParseTuple;
-+ goto cs_failed;
-+ }
-+ link->conf.ConfigBase = parse.config.base;
-+ link->conf.Present = parse.config.rmask[0];
-+
-+ /* Configure card */
-+ link->state |= DEV_CONFIG;
-+ i = CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
-+ tuple.TupleData = (cisdata_t *)buf;
-+ tuple.TupleOffset = 0;
-+ tuple.TupleDataMax = 255;
-+ tuple.Attributes = 0;
-+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+
-+ /* Look for a generic full-sized window */
-+ link->io.NumPorts1 = 8;
-+ i = first_tuple(handle, &tuple, &parse);
-+ while (i != CS_NO_MORE_ITEMS) {
-+ if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-+ link->conf.ConfigIndex = cf->index;
-+ link->io.BasePort1 = cf->io.win[0].base;
-+ link->io.NumPorts1 = cf->io.win[0].len; /*yo */
-+ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-+ i = CardServices(RequestIO, link->handle, &link->io);
-+ if (i == CS_SUCCESS)
-+ break;
-+ }
-+ i = next_tuple(handle, &tuple, &parse);
-+ }
-+
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIO, i);
-+ goto failed;
-+ }
-+
-+ i = CardServices(RequestIRQ, link->handle, &link->irq);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestIRQ, i);
-+ link->irq.AssignedIRQ = 0;
-+ }
-+
-+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+ if (i != CS_SUCCESS) {
-+ cs_error(link->handle, RequestConfiguration, i);
-+ goto failed;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ if (dtl1_open(info) != 0)
-+ goto failed;
-+
-+ strcpy(info->node.dev_name, info->hdev.name);
-+ link->dev = &info->node;
-+ link->state &= ~DEV_CONFIG_PENDING;
-+
-+ return;
-+
-+cs_failed:
-+ cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+ dtl1_release((u_long)link);
-+}
-+
-+
-+void dtl1_release(u_long arg)
-+{
-+ dev_link_t *link = (dev_link_t *)arg;
-+ dtl1_info_t *info = link->priv;
-+
-+ if (link->state & DEV_PRESENT)
-+ dtl1_close(info);
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ link->dev = NULL;
-+
-+ CardServices(ReleaseConfiguration, link->handle);
-+ CardServices(ReleaseIO, link->handle, &link->io);
-+ CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+ link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int dtl1_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+ dev_link_t *link = args->client_data;
-+ dtl1_info_t *info = link->priv;
-+
-+ switch (event) {
-+ case CS_EVENT_CARD_REMOVAL:
-+ link->state &= ~DEV_PRESENT;
-+ if (link->state & DEV_CONFIG) {
-+ dtl1_close(info);
-+ mod_timer(&link->release, jiffies + HZ / 20);
-+ }
-+ break;
-+ case CS_EVENT_CARD_INSERTION:
-+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+ dtl1_config(link);
-+ break;
-+ case CS_EVENT_PM_SUSPEND:
-+ link->state |= DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_RESET_PHYSICAL:
-+ if (link->state & DEV_CONFIG)
-+ CardServices(ReleaseConfiguration, link->handle);
-+ break;
-+ case CS_EVENT_PM_RESUME:
-+ link->state &= ~DEV_SUSPEND;
-+ /* Fall through... */
-+ case CS_EVENT_CARD_RESET:
-+ if (DEV_OK(link))
-+ CardServices(RequestConfiguration, link->handle, &link->conf);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_dtl1_cs(void)
-+{
-+ servinfo_t serv;
-+ int err;
-+
-+ CardServices(GetCardServicesInfo, &serv);
-+ if (serv.Revision != CS_RELEASE_CODE) {
-+ printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
-+ return -1;
-+ }
-+
-+ err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
-+
-+ return err;
-+}
-+
-+
-+void __exit exit_dtl1_cs(void)
-+{
-+ unregister_pccard_driver(&dev_info);
-+
-+ while (dev_list != NULL)
-+ dtl1_detach(dev_list);
-+}
-+
-+
-+module_init(init_dtl1_cs);
-+module_exit(exit_dtl1_cs);
-+
-+EXPORT_NO_SYMBOLS;
-diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.c linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.c
---- linux-2.4.18/drivers/bluetooth/hci_bcsp.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,710 @@
-+/*
-+ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
-+ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
-+
-+ Based on
-+ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com>
-+ ABCSP by Carl Orsborn <cjo@csr.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#define VERSION "0.1"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/fcntl.h>
-+#include <linux/interrupt.h>
-+#include <linux/ptrace.h>
-+#include <linux/poll.h>
-+
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/signal.h>
-+#include <linux/ioctl.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_uart.h"
-+#include "hci_bcsp.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+/* ---- BCSP CRC calculation ---- */
-+
-+/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
-+initial value 0xffff, bits shifted in reverse order. */
-+
-+static const u16 crc_table[] = {
-+ 0x0000, 0x1081, 0x2102, 0x3183,
-+ 0x4204, 0x5285, 0x6306, 0x7387,
-+ 0x8408, 0x9489, 0xa50a, 0xb58b,
-+ 0xc60c, 0xd68d, 0xe70e, 0xf78f
-+};
-+
-+/* Initialise the crc calculator */
-+#define BCSP_CRC_INIT(x) x = 0xffff
-+
-+/*
-+ Update crc with next data byte
-+
-+ Implementation note
-+ The data byte is treated as two nibbles. The crc is generated
-+ in reverse, i.e., bits are fed into the register from the top.
-+*/
-+static void bcsp_crc_update(u16 *crc, u8 d)
-+{
-+ u16 reg = *crc;
-+
-+ reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
-+ reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
-+
-+ *crc = reg;
-+}
-+
-+/*
-+ Get reverse of generated crc
-+
-+ Implementation note
-+ The crc generator (bcsp_crc_init() and bcsp_crc_update())
-+ creates a reversed crc, so it needs to be swapped back before
-+ being passed on.
-+*/
-+static u16 bcsp_crc_reverse(u16 crc)
-+{
-+ u16 b, rev;
-+
-+ for (b = 0, rev = 0; b < 16; b++) {
-+ rev = rev << 1;
-+ rev |= (crc & 1);
-+ crc = crc >> 1;
-+ }
-+ return (rev);
-+}
-+
-+/* ---- BCSP core ---- */
-+
-+static void bcsp_slip_msgdelim(struct sk_buff *skb)
-+{
-+ const char pkt_delim = 0xc0;
-+ memcpy(skb_put(skb, 1), &pkt_delim, 1);
-+}
-+
-+static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
-+{
-+ const char esc_c0[2] = { 0xdb, 0xdc };
-+ const char esc_db[2] = { 0xdb, 0xdd };
-+
-+ switch (c) {
-+ case 0xc0:
-+ memcpy(skb_put(skb, 2), &esc_c0, 2);
-+ break;
-+ case 0xdb:
-+ memcpy(skb_put(skb, 2), &esc_db, 2);
-+ break;
-+ default:
-+ memcpy(skb_put(skb, 1), &c, 1);
-+ }
-+}
-+
-+static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+
-+ if (skb->len > 0xFFF) {
-+ BT_ERR("Packet too long");
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+
-+ switch (skb->pkt_type) {
-+ case HCI_ACLDATA_PKT:
-+ case HCI_COMMAND_PKT:
-+ skb_queue_tail(&bcsp->rel, skb);
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ skb_queue_tail(&bcsp->unrel, skb);
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown packet type");
-+ kfree_skb(skb);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
-+ int len, int pkt_type)
-+{
-+ struct sk_buff *nskb;
-+ u8 hdr[4], chan;
-+ int rel, i;
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
-+#endif
-+
-+ switch (pkt_type) {
-+ case HCI_ACLDATA_PKT:
-+ chan = 6; /* BCSP ACL channel */
-+ rel = 1; /* reliable channel */
-+ break;
-+ case HCI_COMMAND_PKT:
-+ chan = 5; /* BCSP cmd/evt channel */
-+ rel = 1; /* reliable channel */
-+ break;
-+ case HCI_SCODATA_PKT:
-+ chan = 7; /* BCSP SCO channel */
-+ rel = 0; /* unreliable channel */
-+ break;
-+ case BCSP_LE_PKT:
-+ chan = 1; /* BCSP LE channel */
-+ rel = 0; /* unreliable channel */
-+ break;
-+ case BCSP_ACK_PKT:
-+ chan = 0; /* BCSP internal channel */
-+ rel = 0; /* unreliable channel */
-+ break;
-+ default:
-+ BT_ERR("Unknown packet type");
-+ return NULL;
-+ }
-+
-+ /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
-+ (because bytes 0xc0 and 0xdb are escaped, worst case is
-+ when the packet is all made of 0xc0 and 0xdb :) )
-+ + 2 (0xc0 delimiters at start and end). */
-+
-+ nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
-+ if (!nskb)
-+ return NULL;
-+
-+ nskb->pkt_type = pkt_type;
-+
-+ bcsp_slip_msgdelim(nskb);
-+
-+ hdr[0] = bcsp->rxseq_txack << 3;
-+ bcsp->txack_req = 0;
-+ BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
-+
-+ if (rel) {
-+ hdr[0] |= 0x80 + bcsp->msgq_txseq;
-+ BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
-+ bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
-+ }
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ hdr[0] |= 0x40;
-+#endif
-+
-+ hdr[1] = (len << 4) & 0xFF;
-+ hdr[1] |= chan;
-+ hdr[2] = len >> 4;
-+ hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]);
-+
-+ /* Put BCSP header */
-+ for (i = 0; i < 4; i++) {
-+ bcsp_slip_one_byte(nskb, hdr[i]);
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
-+#endif
-+ }
-+
-+ /* Put payload */
-+ for (i = 0; i < len; i++) {
-+ bcsp_slip_one_byte(nskb, data[i]);
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
-+#endif
-+ }
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+ /* Put CRC */
-+ bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
-+ bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
-+ bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
-+#endif
-+
-+ bcsp_slip_msgdelim(nskb);
-+ return nskb;
-+}
-+
-+/* This is a rewrite of pkt_avail in ABCSP */
-+static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
-+ unsigned long flags;
-+ struct sk_buff *skb;
-+
-+ /* First of all, check for unreliable messages in the queue,
-+ since they have priority */
-+
-+ if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
-+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
-+ if (nskb) {
-+ kfree_skb(skb);
-+ return nskb;
-+ } else {
-+ skb_queue_head(&bcsp->unrel, skb);
-+ BT_ERR("Could not dequeue pkt because alloc_skb failed");
-+ }
-+ }
-+
-+ /* Now, try to send a reliable pkt. We can only send a
-+ reliable packet if the number of packets sent but not yet ack'ed
-+ is < than the winsize */
-+
-+ spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+ if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
-+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
-+ if (nskb) {
-+ __skb_queue_tail(&bcsp->unack, skb);
-+ mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+ return nskb;
-+ } else {
-+ skb_queue_head(&bcsp->rel, skb);
-+ BT_ERR("Could not dequeue pkt because alloc_skb failed");
-+ }
-+ }
-+
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+
-+ /* We could not send a reliable packet, either because there are
-+ none or because there are too many unack'ed pkts. Did we receive
-+ any packets we have not acknowledged yet ? */
-+
-+ if (bcsp->txack_req) {
-+ /* if so, craft an empty ACK pkt and send it on BCSP unreliable
-+ channel 0 */
-+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
-+ return nskb;
-+ }
-+
-+ /* We have nothing to send */
-+ return NULL;
-+}
-+
-+static int bcsp_flush(struct hci_uart *hu)
-+{
-+ BT_DBG("hu %p", hu);
-+ return 0;
-+}
-+
-+/* Remove ack'ed packets */
-+static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
-+{
-+ unsigned long flags;
-+ struct sk_buff *skb;
-+ int i, pkts_to_be_removed;
-+ u8 seqno;
-+
-+ spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+ pkts_to_be_removed = bcsp->unack.qlen;
-+ seqno = bcsp->msgq_txseq;
-+
-+ while (pkts_to_be_removed) {
-+ if (bcsp->rxack == seqno)
-+ break;
-+ pkts_to_be_removed--;
-+ seqno = (seqno - 1) & 0x07;
-+ }
-+
-+ if (bcsp->rxack != seqno)
-+ BT_ERR("Peer acked invalid packet");
-+
-+ BT_DBG("Removing %u pkts out of %u, up to seqno %u",
-+ pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
-+
-+ for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
-+ && skb != (struct sk_buff *) &bcsp->unack; i++) {
-+ struct sk_buff *nskb;
-+
-+ nskb = skb->next;
-+ __skb_unlink(skb, &bcsp->unack);
-+ kfree_skb(skb);
-+ skb = nskb;
-+ }
-+ if (bcsp->unack.qlen == 0)
-+ del_timer(&bcsp->tbcsp);
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+ if (i != pkts_to_be_removed)
-+ BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
-+}
-+
-+/* Handle BCSP link-establishment packets. When we
-+ detect a "sync" packet, symptom that the BT module has reset,
-+ we do nothing :) (yet) */
-+static void bcsp_handle_le_pkt(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed };
-+ u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
-+ u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed };
-+
-+ /* spot "conf" pkts and reply with a "conf rsp" pkt */
-+ if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
-+ !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
-+ struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
-+
-+ BT_DBG("Found a LE conf pkt");
-+ if (!nskb)
-+ return;
-+ memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
-+ nskb->pkt_type = BCSP_LE_PKT;
-+
-+ skb_queue_head(&bcsp->unrel, nskb);
-+ hci_uart_tx_wakeup(hu);
-+ }
-+ /* Spot "sync" pkts. If we find one...disaster! */
-+ else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
-+ !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
-+ BT_ERR("Found a LE sync pkt, card has reset");
-+ }
-+}
-+
-+static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
-+{
-+ const u8 c0 = 0xc0, db = 0xdb;
-+
-+ switch (bcsp->rx_esc_state) {
-+ case BCSP_ESCSTATE_NOESC:
-+ switch (byte) {
-+ case 0xdb:
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
-+ break;
-+ default:
-+ memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
-+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
-+ bcsp->rx_state != BCSP_W4_CRC)
-+ bcsp_crc_update(&bcsp->message_crc, byte);
-+ bcsp->rx_count--;
-+ }
-+ break;
-+
-+ case BCSP_ESCSTATE_ESC:
-+ switch (byte) {
-+ case 0xdc:
-+ memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
-+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
-+ bcsp->rx_state != BCSP_W4_CRC)
-+ bcsp_crc_update(&bcsp-> message_crc, 0xc0);
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+ bcsp->rx_count--;
-+ break;
-+
-+ case 0xdd:
-+ memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
-+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
-+ bcsp->rx_state != BCSP_W4_CRC)
-+ bcsp_crc_update(&bcsp-> message_crc, 0xdb);
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+ bcsp->rx_count--;
-+ break;
-+
-+ default:
-+ BT_ERR ("Invalid byte %02x after esc byte", byte);
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_skb = NULL;
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ }
-+ }
-+}
-+
-+static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ int pass_up;
-+
-+ if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */
-+ BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
-+ bcsp->rxseq_txack++;
-+ bcsp->rxseq_txack %= 0x8;
-+ bcsp->txack_req = 1;
-+
-+ /* If needed, transmit an ack pkt */
-+ hci_uart_tx_wakeup(hu);
-+ }
-+
-+ bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
-+ BT_DBG("Request for pkt %u from card", bcsp->rxack);
-+
-+ bcsp_pkt_cull(bcsp);
-+ if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
-+ bcsp->rx_skb->data[0] & 0x80) {
-+ bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
-+ pass_up = 1;
-+ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
-+ bcsp->rx_skb->data[0] & 0x80) {
-+ bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
-+ pass_up = 1;
-+ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
-+ bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
-+ pass_up = 1;
-+ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
-+ !(bcsp->rx_skb->data[0] & 0x80)) {
-+ bcsp_handle_le_pkt(hu);
-+ pass_up = 0;
-+ } else
-+ pass_up = 0;
-+
-+ if (!pass_up) {
-+ if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
-+ (bcsp->rx_skb->data[1] & 0x0f) != 1) {
-+ BT_ERR ("Packet for unknown channel (%u %s)",
-+ bcsp->rx_skb->data[1] & 0x0f,
-+ bcsp->rx_skb->data[0] & 0x80 ?
-+ "reliable" : "unreliable");
-+ }
-+ kfree_skb(bcsp->rx_skb);
-+ } else {
-+ /* Pull out BCSP hdr */
-+ skb_pull(bcsp->rx_skb, 4);
-+
-+ hci_recv_frame(bcsp->rx_skb);
-+ }
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_skb = NULL;
-+}
-+
-+/* Recv data */
-+static int bcsp_recv(struct hci_uart *hu, void *data, int count)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ register unsigned char *ptr;
-+
-+ BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
-+ hu, count, bcsp->rx_state, bcsp->rx_count);
-+
-+ ptr = data;
-+ while (count) {
-+ if (bcsp->rx_count) {
-+ if (*ptr == 0xc0) {
-+ BT_ERR("Short BCSP packet");
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_START;
-+ bcsp->rx_count = 0;
-+ } else
-+ bcsp_unslip_one_byte(bcsp, *ptr);
-+
-+ ptr++; count--;
-+ continue;
-+ }
-+
-+ switch (bcsp->rx_state) {
-+ case BCSP_W4_BCSP_HDR:
-+ if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
-+ bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
-+ BT_ERR("Error in BCSP hdr checksum");
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ continue;
-+ }
-+ if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */
-+ && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
-+ BT_ERR ("Out-of-order packet arrived, got %u expected %u",
-+ bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
-+
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ continue;
-+ }
-+ bcsp->rx_state = BCSP_W4_DATA;
-+ bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) +
-+ (bcsp->rx_skb->data[2] << 4); /* May be 0 */
-+ continue;
-+
-+ case BCSP_W4_DATA:
-+ if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */
-+ bcsp->rx_state = BCSP_W4_CRC;
-+ bcsp->rx_count = 2;
-+ } else
-+ bcsp_complete_rx_pkt(hu);
-+ continue;
-+
-+ case BCSP_W4_CRC:
-+ if (bcsp_crc_reverse(bcsp->message_crc) !=
-+ (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
-+ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
-+
-+ BT_ERR ("Checksum failed: computed %04x received %04x",
-+ bcsp_crc_reverse(bcsp->message_crc),
-+ (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
-+ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
-+
-+ kfree_skb(bcsp->rx_skb);
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ continue;
-+ }
-+ skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
-+ bcsp_complete_rx_pkt(hu);
-+ continue;
-+
-+ case BCSP_W4_PKT_DELIMITER:
-+ switch (*ptr) {
-+ case 0xc0:
-+ bcsp->rx_state = BCSP_W4_PKT_START;
-+ break;
-+ default:
-+ /*BT_ERR("Ignoring byte %02x", *ptr);*/
-+ break;
-+ }
-+ ptr++; count--;
-+ break;
-+
-+ case BCSP_W4_PKT_START:
-+ switch (*ptr) {
-+ case 0xc0:
-+ ptr++; count--;
-+ break;
-+
-+ default:
-+ bcsp->rx_state = BCSP_W4_BCSP_HDR;
-+ bcsp->rx_count = 4;
-+ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+ BCSP_CRC_INIT(bcsp->message_crc);
-+
-+ /* Do not increment ptr or decrement count
-+ * Allocate packet. Max len of a BCSP pkt=
-+ * 0xFFF (payload) +4 (header) +2 (crc) */
-+
-+ bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
-+ if (!bcsp->rx_skb) {
-+ BT_ERR("Can't allocate mem for new packet");
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+ bcsp->rx_count = 0;
-+ return 0;
-+ }
-+ bcsp->rx_skb->dev = (void *) &hu->hdev;
-+ break;
-+ }
-+ break;
-+ }
-+ }
-+ return count;
-+}
-+
-+ /* Arrange to retransmit all messages in the relq. */
-+static void bcsp_timed_event(unsigned long arg)
-+{
-+ struct hci_uart *hu = (struct hci_uart *) arg;
-+ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
-+ struct sk_buff *skb;
-+ unsigned long flags;
-+
-+ BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
-+ spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+ while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
-+ bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
-+ skb_queue_head(&bcsp->rel, skb);
-+ }
-+
-+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+ hci_uart_tx_wakeup(hu);
-+}
-+
-+static int bcsp_open(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
-+ if (!bcsp)
-+ return -ENOMEM;
-+ memset(bcsp, 0, sizeof(*bcsp));
-+
-+ hu->priv = bcsp;
-+ skb_queue_head_init(&bcsp->unack);
-+ skb_queue_head_init(&bcsp->rel);
-+ skb_queue_head_init(&bcsp->unrel);
-+
-+ init_timer(&bcsp->tbcsp);
-+ bcsp->tbcsp.function = bcsp_timed_event;
-+ bcsp->tbcsp.data = (u_long) hu;
-+
-+ bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+
-+ return 0;
-+}
-+
-+static int bcsp_close(struct hci_uart *hu)
-+{
-+ struct bcsp_struct *bcsp = hu->priv;
-+ hu->priv = NULL;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ skb_queue_purge(&bcsp->unack);
-+ skb_queue_purge(&bcsp->rel);
-+ skb_queue_purge(&bcsp->unrel);
-+ del_timer(&bcsp->tbcsp);
-+
-+ kfree(bcsp);
-+ return 0;
-+}
-+
-+static struct hci_uart_proto bcsp = {
-+ id: HCI_UART_BCSP,
-+ open: bcsp_open,
-+ close: bcsp_close,
-+ enqueue: bcsp_enqueue,
-+ dequeue: bcsp_dequeue,
-+ recv: bcsp_recv,
-+ flush: bcsp_flush
-+};
-+
-+int bcsp_init(void)
-+{
-+ return hci_uart_register_proto(&bcsp);
-+}
-+
-+int bcsp_deinit(void)
-+{
-+ return hci_uart_unregister_proto(&bcsp);
-+}
-diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.h linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.h
---- linux-2.4.18/drivers/bluetooth/hci_bcsp.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.h Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,70 @@
-+/*
-+ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
-+ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
-+
-+ Based on
-+ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com>
-+ ABCSP by Carl Orsborn <cjo@csr.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __HCI_BCSP_H__
-+#define __HCI_BCSP_H__
-+
-+#define BCSP_TXWINSIZE 4
-+
-+#define BCSP_ACK_PKT 0x05
-+#define BCSP_LE_PKT 0x06
-+
-+struct bcsp_struct {
-+ struct sk_buff_head unack; /* Unack'ed packets queue */
-+ struct sk_buff_head rel; /* Reliable packets queue */
-+ struct sk_buff_head unrel; /* Unreliable packets queue */
-+
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+ u8 rxseq_txack; /* rxseq == txack. */
-+ u8 rxack; /* Last packet sent by us that the peer ack'ed */
-+ struct timer_list tbcsp;
-+
-+ enum {
-+ BCSP_W4_PKT_DELIMITER,
-+ BCSP_W4_PKT_START,
-+ BCSP_W4_BCSP_HDR,
-+ BCSP_W4_DATA,
-+ BCSP_W4_CRC
-+ } rx_state;
-+
-+ enum {
-+ BCSP_ESCSTATE_NOESC,
-+ BCSP_ESCSTATE_ESC
-+ } rx_esc_state;
-+
-+ u16 message_crc;
-+ u8 txack_req; /* Do we need to send ack's to the peer? */
-+
-+ /* Reliable packet sequence number - used to assign seq to each rel pkt. */
-+ u8 msgq_txseq;
-+};
-+
-+#endif /* __HCI_BCSP_H__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.c linux-2.4.18-mh9/drivers/bluetooth/hci_h4.c
---- linux-2.4.18/drivers/bluetooth/hci_h4.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_h4.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,277 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ HCI UART(H4) protocol.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "1.2"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/fcntl.h>
-+#include <linux/interrupt.h>
-+#include <linux/ptrace.h>
-+#include <linux/poll.h>
-+
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/signal.h>
-+#include <linux/ioctl.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_uart.h"
-+#include "hci_h4.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+/* Initialize protocol */
-+static int h4_open(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
-+ if (!h4)
-+ return -ENOMEM;
-+ memset(h4, 0, sizeof(*h4));
-+
-+ skb_queue_head_init(&h4->txq);
-+
-+ hu->priv = h4;
-+ return 0;
-+}
-+
-+/* Flush protocol data */
-+static int h4_flush(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+
-+ BT_DBG("hu %p", hu);
-+ skb_queue_purge(&h4->txq);
-+ return 0;
-+}
-+
-+/* Close protocol */
-+static int h4_close(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+ hu->priv = NULL;
-+
-+ BT_DBG("hu %p", hu);
-+
-+ skb_queue_purge(&h4->txq);
-+ if (h4->rx_skb)
-+ kfree_skb(h4->rx_skb);
-+
-+ hu->priv = NULL;
-+ kfree(h4);
-+ return 0;
-+}
-+
-+/* Enqueue frame for transmittion (padding, crc, etc) */
-+static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+
-+ BT_DBG("hu %p skb %p", hu, skb);
-+
-+ /* Prepend skb with frame type */
-+ memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-+ skb_queue_tail(&h4->txq, skb);
-+ return 0;
-+}
-+
-+static inline int h4_check_data_len(struct h4_struct *h4, int len)
-+{
-+ register int room = skb_tailroom(h4->rx_skb);
-+
-+ BT_DBG("len %d room %d", len, room);
-+ if (!len) {
-+ BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
-+ hci_recv_frame(h4->rx_skb);
-+ } else if (len > room) {
-+ BT_ERR("Data length is too large");
-+ kfree_skb(h4->rx_skb);
-+ } else {
-+ h4->rx_state = H4_W4_DATA;
-+ h4->rx_count = len;
-+ return len;
-+ }
-+
-+ h4->rx_state = H4_W4_PACKET_TYPE;
-+ h4->rx_skb = NULL;
-+ h4->rx_count = 0;
-+ return 0;
-+}
-+
-+/* Recv data */
-+static int h4_recv(struct hci_uart *hu, void *data, int count)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+ register char *ptr;
-+ hci_event_hdr *eh;
-+ hci_acl_hdr *ah;
-+ hci_sco_hdr *sh;
-+ register int len, type, dlen;
-+
-+ BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
-+ hu, count, h4->rx_state, h4->rx_count);
-+
-+ ptr = data;
-+ while (count) {
-+ if (h4->rx_count) {
-+ len = MIN(h4->rx_count, count);
-+ memcpy(skb_put(h4->rx_skb, len), ptr, len);
-+ h4->rx_count -= len; count -= len; ptr += len;
-+
-+ if (h4->rx_count)
-+ continue;
-+
-+ switch (h4->rx_state) {
-+ case H4_W4_DATA:
-+ BT_DBG("Complete data");
-+
-+ BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
-+
-+ hci_recv_frame(h4->rx_skb);
-+
-+ h4->rx_state = H4_W4_PACKET_TYPE;
-+ h4->rx_skb = NULL;
-+ continue;
-+
-+ case H4_W4_EVENT_HDR:
-+ eh = (hci_event_hdr *) h4->rx_skb->data;
-+
-+ BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
-+
-+ h4_check_data_len(h4, eh->plen);
-+ continue;
-+
-+ case H4_W4_ACL_HDR:
-+ ah = (hci_acl_hdr *) h4->rx_skb->data;
-+ dlen = __le16_to_cpu(ah->dlen);
-+
-+ BT_DBG("ACL header: dlen %d", dlen);
-+
-+ h4_check_data_len(h4, dlen);
-+ continue;
-+
-+ case H4_W4_SCO_HDR:
-+ sh = (hci_sco_hdr *) h4->rx_skb->data;
-+
-+ BT_DBG("SCO header: dlen %d", sh->dlen);
-+
-+ h4_check_data_len(h4, sh->dlen);
-+ continue;
-+ }
-+ }
-+
-+ /* H4_W4_PACKET_TYPE */
-+ switch (*ptr) {
-+ case HCI_EVENT_PKT:
-+ BT_DBG("Event packet");
-+ h4->rx_state = H4_W4_EVENT_HDR;
-+ h4->rx_count = HCI_EVENT_HDR_SIZE;
-+ type = HCI_EVENT_PKT;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ BT_DBG("ACL packet");
-+ h4->rx_state = H4_W4_ACL_HDR;
-+ h4->rx_count = HCI_ACL_HDR_SIZE;
-+ type = HCI_ACLDATA_PKT;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ BT_DBG("SCO packet");
-+ h4->rx_state = H4_W4_SCO_HDR;
-+ h4->rx_count = HCI_SCO_HDR_SIZE;
-+ type = HCI_SCODATA_PKT;
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-+ hu->hdev.stat.err_rx++;
-+ ptr++; count--;
-+ continue;
-+ };
-+ ptr++; count--;
-+
-+ /* Allocate packet */
-+ h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
-+ if (!h4->rx_skb) {
-+ BT_ERR("Can't allocate mem for new packet");
-+ h4->rx_state = H4_W4_PACKET_TYPE;
-+ h4->rx_count = 0;
-+ return 0;
-+ }
-+ h4->rx_skb->dev = (void *) &hu->hdev;
-+ h4->rx_skb->pkt_type = type;
-+ }
-+ return count;
-+}
-+
-+static struct sk_buff *h4_dequeue(struct hci_uart *hu)
-+{
-+ struct h4_struct *h4 = hu->priv;
-+ return skb_dequeue(&h4->txq);
-+}
-+
-+static struct hci_uart_proto h4p = {
-+ id: HCI_UART_H4,
-+ open: h4_open,
-+ close: h4_close,
-+ recv: h4_recv,
-+ enqueue: h4_enqueue,
-+ dequeue: h4_dequeue,
-+ flush: h4_flush,
-+};
-+
-+int h4_init(void)
-+{
-+ return hci_uart_register_proto(&h4p);
-+}
-+
-+int h4_deinit(void)
-+{
-+ return hci_uart_unregister_proto(&h4p);
-+}
-diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.h linux-2.4.18-mh9/drivers/bluetooth/hci_h4.h
---- linux-2.4.18/drivers/bluetooth/hci_h4.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_h4.h Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,44 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifdef __KERNEL__
-+struct h4_struct {
-+ unsigned long rx_state;
-+ unsigned long rx_count;
-+ struct sk_buff *rx_skb;
-+ struct sk_buff_head txq;
-+};
-+
-+/* H4 receiver States */
-+#define H4_W4_PACKET_TYPE 0
-+#define H4_W4_EVENT_HDR 1
-+#define H4_W4_ACL_HDR 2
-+#define H4_W4_SCO_HDR 3
-+#define H4_W4_DATA 4
-+
-+#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_ldisc.c linux-2.4.18-mh9/drivers/bluetooth/hci_ldisc.c
---- linux-2.4.18/drivers/bluetooth/hci_ldisc.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_ldisc.c Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,580 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ HCI UART driver.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "2.1"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/fcntl.h>
-+#include <linux/interrupt.h>
-+#include <linux/ptrace.h>
-+#include <linux/poll.h>
-+
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/signal.h>
-+#include <linux/ioctl.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_uart.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
-+
-+int hci_uart_register_proto(struct hci_uart_proto *p)
-+{
-+ if (p->id >= HCI_UART_MAX_PROTO)
-+ return -EINVAL;
-+
-+ if (hup[p->id])
-+ return -EEXIST;
-+
-+ hup[p->id] = p;
-+ return 0;
-+}
-+
-+int hci_uart_unregister_proto(struct hci_uart_proto *p)
-+{
-+ if (p->id >= HCI_UART_MAX_PROTO)
-+ return -EINVAL;
-+
-+ if (!hup[p->id])
-+ return -EINVAL;
-+
-+ hup[p->id] = NULL;
-+ return 0;
-+}
-+
-+static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
-+{
-+ if (id >= HCI_UART_MAX_PROTO)
-+ return NULL;
-+ return hup[id];
-+}
-+
-+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
-+{
-+ struct hci_dev *hdev = &hu->hdev;
-+
-+ /* Update HCI stat counters */
-+ switch (pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+ }
-+}
-+
-+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
-+{
-+ struct sk_buff *skb = hu->tx_skb;
-+ if (!skb)
-+ skb = hu->proto->dequeue(hu);
-+ else
-+ hu->tx_skb = NULL;
-+ return skb;
-+}
-+
-+int hci_uart_tx_wakeup(struct hci_uart *hu)
-+{
-+ struct tty_struct *tty = hu->tty;
-+ struct hci_dev *hdev = &hu->hdev;
-+ struct sk_buff *skb;
-+
-+ if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
-+ set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
-+ return 0;
-+ }
-+
-+ BT_DBG("");
-+
-+restart:
-+ clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
-+
-+ while ((skb = hci_uart_dequeue(hu))) {
-+ int len;
-+
-+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-+ len = tty->driver.write(tty, 0, skb->data, skb->len);
-+ hdev->stat.byte_tx += len;
-+
-+ skb_pull(skb, len);
-+ if (skb->len) {
-+ hu->tx_skb = skb;
-+ break;
-+ }
-+
-+ hci_uart_tx_complete(hu, skb->pkt_type);
-+ kfree_skb(skb);
-+ }
-+
-+ if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
-+ goto restart;
-+
-+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
-+ return 0;
-+}
-+
-+/* ------- Interface to HCI layer ------ */
-+/* Initialize device */
-+static int hci_uart_open(struct hci_dev *hdev)
-+{
-+ BT_DBG("%s %p", hdev->name, hdev);
-+
-+ /* Nothing to do for UART driver */
-+
-+ set_bit(HCI_RUNNING, &hdev->flags);
-+ return 0;
-+}
-+
-+/* Reset device */
-+static int hci_uart_flush(struct hci_dev *hdev)
-+{
-+ struct hci_uart *hu = (struct hci_uart *) hdev->driver_data;
-+ struct tty_struct *tty = hu->tty;
-+
-+ BT_DBG("hdev %p tty %p", hdev, tty);
-+
-+ if (hu->tx_skb) {
-+ kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
-+ }
-+
-+ /* Flush any pending characters in the driver and discipline. */
-+ if (tty->ldisc.flush_buffer)
-+ tty->ldisc.flush_buffer(tty);
-+
-+ if (tty->driver.flush_buffer)
-+ tty->driver.flush_buffer(tty);
-+
-+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ hu->proto->flush(hu);
-+
-+ return 0;
-+}
-+
-+/* Close device */
-+static int hci_uart_close(struct hci_dev *hdev)
-+{
-+ BT_DBG("hdev %p", hdev);
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
-+ hci_uart_flush(hdev);
-+ return 0;
-+}
-+
-+/* Send frames from HCI layer */
-+static int hci_uart_send_frame(struct sk_buff *skb)
-+{
-+ struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-+ struct tty_struct *tty;
-+ struct hci_uart *hu;
-+
-+ if (!hdev) {
-+ BT_ERR("Frame for uknown device (hdev=NULL)");
-+ return -ENODEV;
-+ }
-+
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-+
-+ hu = (struct hci_uart *) hdev->driver_data;
-+ tty = hu->tty;
-+
-+ BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+
-+ hu->proto->enqueue(hu, skb);
-+
-+ hci_uart_tx_wakeup(hu);
-+ return 0;
-+}
-+
-+static void hci_uart_destruct(struct hci_dev *hdev)
-+{
-+ struct hci_uart *hu;
-+
-+ if (!hdev) return;
-+
-+ BT_DBG("%s", hdev->name);
-+
-+ hu = (struct hci_uart *) hdev->driver_data;
-+ kfree(hu);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* ------ LDISC part ------ */
-+/* hci_uart_tty_open
-+ *
-+ * Called when line discipline changed to HCI_UART.
-+ *
-+ * Arguments:
-+ * tty pointer to tty info structure
-+ * Return Value:
-+ * 0 if success, otherwise error code
-+ */
-+static int hci_uart_tty_open(struct tty_struct *tty)
-+{
-+ struct hci_uart *hu = (void *) tty->disc_data;
-+
-+ BT_DBG("tty %p", tty);
-+
-+ if (hu)
-+ return -EEXIST;
-+
-+ if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
-+ BT_ERR("Can't allocate controll structure");
-+ return -ENFILE;
-+ }
-+ memset(hu, 0, sizeof(struct hci_uart));
-+
-+ tty->disc_data = hu;
-+ hu->tty = tty;
-+
-+ spin_lock_init(&hu->rx_lock);
-+
-+ /* Flush any pending characters in the driver and line discipline */
-+ if (tty->ldisc.flush_buffer)
-+ tty->ldisc.flush_buffer(tty);
-+
-+ if (tty->driver.flush_buffer)
-+ tty->driver.flush_buffer(tty);
-+
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+/* hci_uart_tty_close()
-+ *
-+ * Called when the line discipline is changed to something
-+ * else, the tty is closed, or the tty detects a hangup.
-+ */
-+static void hci_uart_tty_close(struct tty_struct *tty)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+
-+ BT_DBG("tty %p", tty);
-+
-+ /* Detach from the tty */
-+ tty->disc_data = NULL;
-+
-+ if (hu) {
-+ struct hci_dev *hdev = &hu->hdev;
-+ hci_uart_close(hdev);
-+
-+ if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-+ hu->proto->close(hu);
-+ hci_unregister_dev(hdev);
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+ }
-+}
-+
-+/* hci_uart_tty_wakeup()
-+ *
-+ * Callback for transmit wakeup. Called when low level
-+ * device driver can accept more send data.
-+ *
-+ * Arguments: tty pointer to associated tty instance data
-+ * Return Value: None
-+ */
-+static void hci_uart_tty_wakeup(struct tty_struct *tty)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+
-+ BT_DBG("");
-+
-+ if (!hu)
-+ return;
-+
-+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-+
-+ if (tty != hu->tty)
-+ return;
-+
-+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ hci_uart_tx_wakeup(hu);
-+}
-+
-+/* hci_uart_tty_room()
-+ *
-+ * Callback function from tty driver. Return the amount of
-+ * space left in the receiver's buffer to decide if remote
-+ * transmitter is to be throttled.
-+ *
-+ * Arguments: tty pointer to associated tty instance data
-+ * Return Value: number of bytes left in receive buffer
-+ */
-+static int hci_uart_tty_room (struct tty_struct *tty)
-+{
-+ return 65536;
-+}
-+
-+/* hci_uart_tty_receive()
-+ *
-+ * Called by tty low level driver when receive data is
-+ * available.
-+ *
-+ * Arguments: tty pointer to tty isntance data
-+ * data pointer to received data
-+ * flags pointer to flags for data
-+ * count count of received data in bytes
-+ *
-+ * Return Value: None
-+ */
-+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+
-+ if (!hu || tty != hu->tty)
-+ return;
-+
-+ if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ return;
-+
-+ spin_lock(&hu->rx_lock);
-+ hu->proto->recv(hu, (void *) data, count);
-+ hu->hdev.stat.byte_rx += count;
-+ spin_unlock(&hu->rx_lock);
-+
-+ if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
-+ tty->driver.unthrottle(tty);
-+}
-+
-+static int hci_uart_register_dev(struct hci_uart *hu)
-+{
-+ struct hci_dev *hdev;
-+
-+ BT_DBG("");
-+
-+ /* Initialize and register HCI device */
-+ hdev = &hu->hdev;
-+
-+ hdev->type = HCI_UART;
-+ hdev->driver_data = hu;
-+
-+ hdev->open = hci_uart_open;
-+ hdev->close = hci_uart_close;
-+ hdev->flush = hci_uart_flush;
-+ hdev->send = hci_uart_send_frame;
-+ hdev->destruct = hci_uart_destruct;
-+
-+ if (hci_register_dev(hdev) < 0) {
-+ BT_ERR("Can't register HCI device %s", hdev->name);
-+ return -ENODEV;
-+ }
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int hci_uart_set_proto(struct hci_uart *hu, int id)
-+{
-+ struct hci_uart_proto *p;
-+ int err;
-+
-+ p = hci_uart_get_proto(id);
-+ if (!p)
-+ return -EPROTONOSUPPORT;
-+
-+ err = p->open(hu);
-+ if (err)
-+ return err;
-+
-+ hu->proto = p;
-+
-+ err = hci_uart_register_dev(hu);
-+ if (err) {
-+ p->close(hu);
-+ return err;
-+ }
-+ return 0;
-+}
-+
-+/* hci_uart_tty_ioctl()
-+ *
-+ * Process IOCTL system call for the tty device.
-+ *
-+ * Arguments:
-+ *
-+ * tty pointer to tty instance data
-+ * file pointer to open file object for device
-+ * cmd IOCTL command code
-+ * arg argument for IOCTL call (cmd dependent)
-+ *
-+ * Return Value: Command dependent
-+ */
-+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct hci_uart *hu = (void *)tty->disc_data;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ /* Verify the status of the device */
-+ if (!hu)
-+ return -EBADF;
-+
-+ switch (cmd) {
-+ case HCIUARTSETPROTO:
-+ if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-+ err = hci_uart_set_proto(hu, arg);
-+ if (err) {
-+ clear_bit(HCI_UART_PROTO_SET, &hu->flags);
-+ return err;
-+ }
-+ tty->low_latency = 1;
-+ } else
-+ return -EBUSY;
-+
-+ case HCIUARTGETPROTO:
-+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+ return hu->proto->id;
-+ return -EUNATCH;
-+
-+ default:
-+ err = n_tty_ioctl(tty, file, cmd, arg);
-+ break;
-+ };
-+
-+ return err;
-+}
-+
-+/*
-+ * We don't provide read/write/poll interface for user space.
-+ */
-+static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
-+{
-+ return 0;
-+}
-+static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
-+{
-+ return 0;
-+}
-+static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
-+{
-+ return 0;
-+}
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+int h4_init(void);
-+int h4_deinit(void);
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+int bcsp_init(void);
-+int bcsp_deinit(void);
-+#endif
-+
-+int __init hci_uart_init(void)
-+{
-+ static struct tty_ldisc hci_uart_ldisc;
-+ int err;
-+
-+ BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ VERSION);
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+
-+ /* Register the tty discipline */
-+
-+ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
-+ hci_uart_ldisc.magic = TTY_LDISC_MAGIC;
-+ hci_uart_ldisc.name = "n_hci";
-+ hci_uart_ldisc.open = hci_uart_tty_open;
-+ hci_uart_ldisc.close = hci_uart_tty_close;
-+ hci_uart_ldisc.read = hci_uart_tty_read;
-+ hci_uart_ldisc.write = hci_uart_tty_write;
-+ hci_uart_ldisc.ioctl = hci_uart_tty_ioctl;
-+ hci_uart_ldisc.poll = hci_uart_tty_poll;
-+ hci_uart_ldisc.receive_room= hci_uart_tty_room;
-+ hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
-+ hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
-+
-+ if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
-+ BT_ERR("Can't register HCI line discipline (%d)", err);
-+ return err;
-+ }
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+ h4_init();
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+ bcsp_init();
-+#endif
-+
-+ return 0;
-+}
-+
-+void hci_uart_cleanup(void)
-+{
-+ int err;
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+ h4_deinit();
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+ bcsp_deinit();
-+#endif
-+
-+ /* Release tty registration of line discipline */
-+ if ((err = tty_register_ldisc(N_HCI, NULL)))
-+ BT_ERR("Can't unregister HCI line discipline (%d)", err);
-+}
-+
-+module_init(hci_uart_init);
-+module_exit(hci_uart_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.c linux-2.4.18-mh9/drivers/bluetooth/hci_uart.c
---- linux-2.4.18/drivers/bluetooth/hci_uart.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_uart.c Thu Jan 1 01:00:00 1970
-@@ -1,580 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * BlueZ HCI UART driver.
-- *
-- * $Id$
-- */
--#define VERSION "1.0"
--
--#include <linux/config.h>
--#include <linux/module.h>
--
--#include <linux/version.h>
--#include <linux/config.h>
--#include <linux/kernel.h>
--#include <linux/init.h>
--#include <linux/sched.h>
--#include <linux/types.h>
--#include <linux/fcntl.h>
--#include <linux/interrupt.h>
--#include <linux/ptrace.h>
--#include <linux/poll.h>
--
--#include <linux/slab.h>
--#include <linux/tty.h>
--#include <linux/errno.h>
--#include <linux/string.h>
--#include <linux/signal.h>
--#include <linux/ioctl.h>
--#include <linux/skbuff.h>
--
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_uart.h>
--
--#ifndef HCI_UART_DEBUG
--#undef DBG
--#define DBG( A... )
--#undef DMP
--#define DMP( A... )
--#endif
--
--/* ------- Interface to HCI layer ------ */
--/* Initialize device */
--int n_hci_open(struct hci_dev *hdev)
--{
-- DBG("%s %p", hdev->name, hdev);
--
-- /* Nothing to do for UART driver */
--
-- hdev->flags |= HCI_RUNNING;
--
-- return 0;
--}
--
--/* Reset device */
--int n_hci_flush(struct hci_dev *hdev)
--{
-- struct n_hci *n_hci = (struct n_hci *) hdev->driver_data;
-- struct tty_struct *tty = n_hci->tty;
--
-- DBG("hdev %p tty %p", hdev, tty);
--
-- /* Drop TX queue */
-- skb_queue_purge(&n_hci->txq);
--
-- /* Flush any pending characters in the driver and discipline. */
-- if (tty->ldisc.flush_buffer)
-- tty->ldisc.flush_buffer(tty);
--
-- if (tty->driver.flush_buffer)
-- tty->driver.flush_buffer(tty);
--
-- return 0;
--}
--
--/* Close device */
--int n_hci_close(struct hci_dev *hdev)
--{
-- DBG("hdev %p", hdev);
--
-- hdev->flags &= ~HCI_RUNNING;
--
-- n_hci_flush(hdev);
--
-- return 0;
--}
--
--int n_hci_tx_wakeup(struct n_hci *n_hci)
--{
-- register struct tty_struct *tty = n_hci->tty;
--
-- if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
-- set_bit(TRANS_WAKEUP, &n_hci->tx_state);
-- return 0;
-- }
--
-- DBG("");
-- do {
-- register struct sk_buff *skb;
-- register int len;
--
-- clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
--
-- if (!(skb = skb_dequeue(&n_hci->txq)))
-- break;
--
-- DMP(skb->data, skb->len);
--
-- /* Send frame to TTY driver */
-- tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-- len = tty->driver.write(tty, 0, skb->data, skb->len);
--
-- n_hci->hdev.stat.byte_tx += len;
--
-- DBG("sent %d", len);
--
-- if (len == skb->len) {
-- /* Full frame was sent */
-- kfree_skb(skb);
-- } else {
-- /* Subtract sent part and requeue */
-- skb_pull(skb, len);
-- skb_queue_head(&n_hci->txq, skb);
-- }
-- } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
-- clear_bit(TRANS_SENDING, &n_hci->tx_state);
--
-- return 0;
--}
--
--/* Send frames from HCI layer */
--int n_hci_send_frame(struct sk_buff *skb)
--{
-- struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-- struct tty_struct *tty;
-- struct n_hci *n_hci;
--
-- if (!hdev) {
-- ERR("Frame for uknown device (hdev=NULL)");
-- return -ENODEV;
-- }
--
-- if (!(hdev->flags & HCI_RUNNING))
-- return -EBUSY;
--
-- n_hci = (struct n_hci *) hdev->driver_data;
-- tty = n_hci2tty(n_hci);
--
-- DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
-- switch (skb->pkt_type) {
-- case HCI_COMMAND_PKT:
-- hdev->stat.cmd_tx++;
-- break;
--
-- case HCI_ACLDATA_PKT:
-- hdev->stat.acl_tx++;
-- break;
--
-- case HCI_SCODATA_PKT:
-- hdev->stat.cmd_tx++;
-- break;
-- };
--
-- /* Prepend skb with frame type and queue */
-- memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-- skb_queue_tail(&n_hci->txq, skb);
--
-- n_hci_tx_wakeup(n_hci);
--
-- return 0;
--}
--
--/* ------ LDISC part ------ */
--
--/* n_hci_tty_open
-- *
-- * Called when line discipline changed to N_HCI.
-- *
-- * Arguments:
-- * tty pointer to tty info structure
-- * Return Value:
-- * 0 if success, otherwise error code
-- */
--static int n_hci_tty_open(struct tty_struct *tty)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
-- struct hci_dev *hdev;
--
-- DBG("tty %p", tty);
--
-- if (n_hci)
-- return -EEXIST;
--
-- if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
-- ERR("Can't allocate controll structure");
-- return -ENFILE;
-- }
-- memset(n_hci, 0, sizeof(struct n_hci));
--
-- /* Initialize and register HCI device */
-- hdev = &n_hci->hdev;
--
-- hdev->type = HCI_UART;
-- hdev->driver_data = n_hci;
--
-- hdev->open = n_hci_open;
-- hdev->close = n_hci_close;
-- hdev->flush = n_hci_flush;
-- hdev->send = n_hci_send_frame;
--
-- if (hci_register_dev(hdev) < 0) {
-- ERR("Can't register HCI device %s", hdev->name);
-- kfree(n_hci);
-- return -ENODEV;
-- }
--
-- tty->disc_data = n_hci;
-- n_hci->tty = tty;
--
-- spin_lock_init(&n_hci->rx_lock);
-- n_hci->rx_state = WAIT_PACKET_TYPE;
--
-- skb_queue_head_init(&n_hci->txq);
--
-- MOD_INC_USE_COUNT;
--
-- /* Flush any pending characters in the driver and discipline. */
-- if (tty->ldisc.flush_buffer)
-- tty->ldisc.flush_buffer(tty);
--
-- if (tty->driver.flush_buffer)
-- tty->driver.flush_buffer(tty);
--
-- return 0;
--}
--
--/* n_hci_tty_close()
-- *
-- * Called when the line discipline is changed to something
-- * else, the tty is closed, or the tty detects a hangup.
-- */
--static void n_hci_tty_close(struct tty_struct *tty)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
-- struct hci_dev *hdev = &n_hci->hdev;
--
-- DBG("tty %p hdev %p", tty, hdev);
--
-- if (n_hci != NULL) {
-- n_hci_close(hdev);
--
-- if (hci_unregister_dev(hdev) < 0) {
-- ERR("Can't unregister HCI device %s",hdev->name);
-- }
--
-- hdev->driver_data = NULL;
-- tty->disc_data = NULL;
-- kfree(n_hci);
--
-- MOD_DEC_USE_COUNT;
-- }
--}
--
--/* n_hci_tty_wakeup()
-- *
-- * Callback for transmit wakeup. Called when low level
-- * device driver can accept more send data.
-- *
-- * Arguments: tty pointer to associated tty instance data
-- * Return Value: None
-- */
--static void n_hci_tty_wakeup( struct tty_struct *tty )
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
--
-- DBG("");
--
-- if (!n_hci)
-- return;
--
-- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
--
-- if (tty != n_hci->tty)
-- return;
--
-- n_hci_tx_wakeup(n_hci);
--}
--
--/* n_hci_tty_room()
-- *
-- * Callback function from tty driver. Return the amount of
-- * space left in the receiver's buffer to decide if remote
-- * transmitter is to be throttled.
-- *
-- * Arguments: tty pointer to associated tty instance data
-- * Return Value: number of bytes left in receive buffer
-- */
--static int n_hci_tty_room (struct tty_struct *tty)
--{
-- return 65536;
--}
--
--static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
--{
-- register int room = skb_tailroom(n_hci->rx_skb);
--
-- DBG("len %d room %d", len, room);
-- if (!len) {
-- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
-- hci_recv_frame(n_hci->rx_skb);
-- } else if (len > room) {
-- ERR("Data length is to large");
-- kfree_skb(n_hci->rx_skb);
-- n_hci->hdev.stat.err_rx++;
-- } else {
-- n_hci->rx_state = WAIT_DATA;
-- n_hci->rx_count = len;
-- return len;
-- }
--
-- n_hci->rx_state = WAIT_PACKET_TYPE;
-- n_hci->rx_skb = NULL;
-- n_hci->rx_count = 0;
-- return 0;
--}
--
--static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
--{
-- register const char *ptr;
-- hci_event_hdr *eh;
-- hci_acl_hdr *ah;
-- hci_sco_hdr *sh;
-- register int len, type, dlen;
--
-- DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);
--
-- n_hci->hdev.stat.byte_rx += count;
--
-- ptr = data;
-- while (count) {
-- if (n_hci->rx_count) {
-- len = MIN(n_hci->rx_count, count);
-- memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
-- n_hci->rx_count -= len; count -= len; ptr += len;
--
-- if (n_hci->rx_count)
-- continue;
--
-- switch (n_hci->rx_state) {
-- case WAIT_DATA:
-- DBG("Complete data");
--
-- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
--
-- hci_recv_frame(n_hci->rx_skb);
--
-- n_hci->rx_state = WAIT_PACKET_TYPE;
-- n_hci->rx_skb = NULL;
-- continue;
--
-- case WAIT_EVENT_HDR:
-- eh = (hci_event_hdr *) n_hci->rx_skb->data;
--
-- DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
--
-- n_hci_check_data_len(n_hci, eh->plen);
-- continue;
--
-- case WAIT_ACL_HDR:
-- ah = (hci_acl_hdr *) n_hci->rx_skb->data;
-- dlen = __le16_to_cpu(ah->dlen);
--
-- DBG("ACL header: dlen %d", dlen);
--
-- n_hci_check_data_len(n_hci, dlen);
-- continue;
--
-- case WAIT_SCO_HDR:
-- sh = (hci_sco_hdr *) n_hci->rx_skb->data;
--
-- DBG("SCO header: dlen %d", sh->dlen);
--
-- n_hci_check_data_len(n_hci, sh->dlen);
-- continue;
-- };
-- }
--
-- /* WAIT_PACKET_TYPE */
-- switch (*ptr) {
-- case HCI_EVENT_PKT:
-- DBG("Event packet");
-- n_hci->rx_state = WAIT_EVENT_HDR;
-- n_hci->rx_count = HCI_EVENT_HDR_SIZE;
-- type = HCI_EVENT_PKT;
-- break;
--
-- case HCI_ACLDATA_PKT:
-- DBG("ACL packet");
-- n_hci->rx_state = WAIT_ACL_HDR;
-- n_hci->rx_count = HCI_ACL_HDR_SIZE;
-- type = HCI_ACLDATA_PKT;
-- break;
--
-- case HCI_SCODATA_PKT:
-- DBG("SCO packet");
-- n_hci->rx_state = WAIT_SCO_HDR;
-- n_hci->rx_count = HCI_SCO_HDR_SIZE;
-- type = HCI_SCODATA_PKT;
-- break;
--
-- default:
-- ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-- n_hci->hdev.stat.err_rx++;
-- ptr++; count--;
-- continue;
-- };
-- ptr++; count--;
--
-- /* Allocate packet */
-- if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-- ERR("Can't allocate mem for new packet");
--
-- n_hci->rx_state = WAIT_PACKET_TYPE;
-- n_hci->rx_count = 0;
-- return;
-- }
-- n_hci->rx_skb->dev = (void *) &n_hci->hdev;
-- n_hci->rx_skb->pkt_type = type;
-- }
--}
--
--/* n_hci_tty_receive()
-- *
-- * Called by tty low level driver when receive data is
-- * available.
-- *
-- * Arguments: tty pointer to tty isntance data
-- * data pointer to received data
-- * flags pointer to flags for data
-- * count count of received data in bytes
-- *
-- * Return Value: None
-- */
--static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
--
-- if (!n_hci || tty != n_hci->tty)
-- return;
--
-- spin_lock(&n_hci->rx_lock);
-- n_hci_rx(n_hci, data, flags, count);
-- spin_unlock(&n_hci->rx_lock);
--
-- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
-- tty->driver.unthrottle(tty);
--}
--
--/* n_hci_tty_ioctl()
-- *
-- * Process IOCTL system call for the tty device.
-- *
-- * Arguments:
-- *
-- * tty pointer to tty instance data
-- * file pointer to open file object for device
-- * cmd IOCTL command code
-- * arg argument for IOCTL call (cmd dependent)
-- *
-- * Return Value: Command dependent
-- */
--static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
-- unsigned int cmd, unsigned long arg)
--{
-- struct n_hci *n_hci = tty2n_hci(tty);
-- int error = 0;
--
-- DBG("");
--
-- /* Verify the status of the device */
-- if (!n_hci)
-- return -EBADF;
--
-- switch (cmd) {
-- default:
-- error = n_tty_ioctl(tty, file, cmd, arg);
-- break;
-- };
--
-- return error;
--}
--
--/*
-- * We don't provide read/write/poll interface for user space.
-- */
--static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
--{
-- return 0;
--}
--static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
--{
-- return 0;
--}
--static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
--{
-- return 0;
--}
--
--int __init n_hci_init(void)
--{
-- static struct tty_ldisc n_hci_ldisc;
-- int err;
--
-- INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
--
-- /* Register the tty discipline */
--
-- memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
-- n_hci_ldisc.magic = TTY_LDISC_MAGIC;
-- n_hci_ldisc.name = "n_hci";
-- n_hci_ldisc.open = n_hci_tty_open;
-- n_hci_ldisc.close = n_hci_tty_close;
-- n_hci_ldisc.read = n_hci_tty_read;
-- n_hci_ldisc.write = n_hci_tty_write;
-- n_hci_ldisc.ioctl = n_hci_tty_ioctl;
-- n_hci_ldisc.poll = n_hci_tty_poll;
-- n_hci_ldisc.receive_room= n_hci_tty_room;
-- n_hci_ldisc.receive_buf = n_hci_tty_receive;
-- n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
--
-- if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
-- ERR("Can't register HCI line discipline (%d)", err);
-- return err;
-- }
--
-- return 0;
--}
--
--void n_hci_cleanup(void)
--{
-- int err;
--
-- /* Release tty registration of line discipline */
-- if ((err = tty_register_ldisc(N_HCI, NULL)))
-- ERR("Can't unregister HCI line discipline (%d)", err);
--}
--
--module_init(n_hci_init);
--module_exit(n_hci_cleanup);
--
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
--MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.h linux-2.4.18-mh9/drivers/bluetooth/hci_uart.h
---- linux-2.4.18/drivers/bluetooth/hci_uart.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_uart.h Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,81 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef N_HCI
-+#define N_HCI 15
-+#endif
-+
-+/* Ioctls */
-+#define HCIUARTSETPROTO _IOW('U', 200, int)
-+#define HCIUARTGETPROTO _IOR('U', 201, int)
-+
-+/* UART protocols */
-+#define HCI_UART_MAX_PROTO 3
-+
-+#define HCI_UART_H4 0
-+#define HCI_UART_BCSP 1
-+#define HCI_UART_NCSP 2
-+
-+#ifdef __KERNEL__
-+struct hci_uart;
-+
-+struct hci_uart_proto {
-+ unsigned int id;
-+ int (*open)(struct hci_uart *hu);
-+ int (*close)(struct hci_uart *hu);
-+ int (*flush)(struct hci_uart *hu);
-+ int (*recv)(struct hci_uart *hu, void *data, int len);
-+ int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
-+ struct sk_buff *(*dequeue)(struct hci_uart *hu);
-+};
-+
-+struct hci_uart {
-+ struct tty_struct *tty;
-+ struct hci_dev hdev;
-+ unsigned long flags;
-+
-+ struct hci_uart_proto *proto;
-+ void *priv;
-+
-+ struct sk_buff *tx_skb;
-+ unsigned long tx_state;
-+ spinlock_t rx_lock;
-+};
-+
-+/* HCI_UART flag bits */
-+#define HCI_UART_PROTO_SET 0
-+
-+/* TX states */
-+#define HCI_UART_SENDING 1
-+#define HCI_UART_TX_WAKEUP 2
-+
-+int hci_uart_register_proto(struct hci_uart_proto *p);
-+int hci_uart_unregister_proto(struct hci_uart_proto *p);
-+int hci_uart_tx_wakeup(struct hci_uart *hu);
-+
-+#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.c linux-2.4.18-mh9/drivers/bluetooth/hci_usb.c
---- linux-2.4.18/drivers/bluetooth/hci_usb.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_usb.c Mon Aug 25 18:38:12 2003
-@@ -1,9 +1,10 @@
- /*
-- BlueZ - Bluetooth protocol stack for Linux
-+ HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
- Copyright (C) 2000-2001 Qualcomm Incorporated
--
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-+ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
-+
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-@@ -23,598 +24,901 @@
- */
-
- /*
-- * BlueZ HCI USB driver.
- * Based on original USB Bluetooth driver for Linux kernel
- * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
- *
-- * $Id$
-+ * $Id$
- */
--#define VERSION "1.0"
-+#define VERSION "2.4"
-
- #include <linux/config.h>
- #include <linux/module.h>
-
- #include <linux/version.h>
--#include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/sched.h>
-+#include <linux/unistd.h>
- #include <linux/types.h>
--#include <linux/fcntl.h>
- #include <linux/interrupt.h>
--#include <linux/ptrace.h>
--#include <linux/poll.h>
-
- #include <linux/slab.h>
--#include <linux/tty.h>
- #include <linux/errno.h>
- #include <linux/string.h>
--#include <linux/signal.h>
--#include <linux/ioctl.h>
- #include <linux/skbuff.h>
-
- #include <linux/usb.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_usb.h>
-+
-+#include "hci_usb.h"
-
- #ifndef HCI_USB_DEBUG
--#undef DBG
--#define DBG( A... )
--#undef DMP
--#define DMP( A... )
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#undef BT_DMP
-+#define BT_DMP( A... )
- #endif
-
--static struct usb_device_id usb_bluetooth_ids [] = {
-+#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET
-+#undef USB_ZERO_PACKET
-+#define USB_ZERO_PACKET 0
-+#endif
-+
-+static struct usb_driver hci_usb_driver;
-+
-+static struct usb_device_id bluetooth_ids[] = {
-+ /* Generic Bluetooth USB device */
- { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
-+
-+ /* Ericsson with non-standard id */
-+ { USB_DEVICE(0x0bdb, 0x1002) },
-+
-+ /* Bluetooth Ultraport Module from IBM */
-+ { USB_DEVICE(0x04bf, 0x030a) },
-+
- { } /* Terminating entry */
- };
-
--MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
-+MODULE_DEVICE_TABLE (usb, bluetooth_ids);
-
--static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb);
--static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
-+static struct usb_device_id ignore_ids[] = {
-+ /* Broadcom BCM2033 without firmware */
-+ { USB_DEVICE(0x0a5c, 0x2033) },
-
--static void hci_usb_unlink_urbs(struct hci_usb *husb)
--{
-- usb_unlink_urb(husb->read_urb);
-- usb_unlink_urb(husb->intr_urb);
-- usb_unlink_urb(husb->ctrl_urb);
-- usb_unlink_urb(husb->write_urb);
--}
-+ { } /* Terminating entry */
-+};
-
--static void hci_usb_free_bufs(struct hci_usb *husb)
-+struct _urb *_urb_alloc(int isoc, int gfp)
- {
-- if (husb->read_urb) {
-- if (husb->read_urb->transfer_buffer)
-- kfree(husb->read_urb->transfer_buffer);
-- usb_free_urb(husb->read_urb);
-- }
--
-- if (husb->intr_urb) {
-- if (husb->intr_urb->transfer_buffer)
-- kfree(husb->intr_urb->transfer_buffer);
-- usb_free_urb(husb->intr_urb);
-+ struct _urb *_urb = kmalloc(sizeof(struct _urb) +
-+ sizeof(iso_packet_descriptor_t) * isoc, gfp);
-+ if (_urb) {
-+ memset(_urb, 0, sizeof(*_urb));
-+ spin_lock_init(&_urb->urb.lock);
-+ }
-+ return _urb;
-+}
-+
-+struct _urb *_urb_dequeue(struct _urb_queue *q)
-+{
-+ struct _urb *_urb = NULL;
-+ unsigned long flags;
-+ spin_lock_irqsave(&q->lock, flags);
-+ {
-+ struct list_head *head = &q->head;
-+ struct list_head *next = head->next;
-+ if (next != head) {
-+ _urb = list_entry(next, struct _urb, list);
-+ list_del(next); _urb->queue = NULL;
-+ }
- }
-+ spin_unlock_irqrestore(&q->lock, flags);
-+ return _urb;
-+}
-
-- if (husb->ctrl_urb)
-- usb_free_urb(husb->ctrl_urb);
-+static void hci_usb_rx_complete(struct urb *urb);
-+static void hci_usb_tx_complete(struct urb *urb);
-
-- if (husb->write_urb)
-- usb_free_urb(husb->write_urb);
-+#define __pending_tx(husb, type) (&husb->pending_tx[type-1])
-+#define __pending_q(husb, type) (&husb->pending_q[type-1])
-+#define __completed_q(husb, type) (&husb->completed_q[type-1])
-+#define __transmit_q(husb, type) (&husb->transmit_q[type-1])
-+#define __reassembly(husb, type) (husb->reassembly[type-1])
-
-- if (husb->intr_skb)
-- kfree_skb(husb->intr_skb);
-+static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
-+{
-+ return _urb_dequeue(__completed_q(husb, type));
- }
-
--/* ------- Interface to HCI layer ------ */
--/* Initialize device */
--int hci_usb_open(struct hci_dev *hdev)
-+static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
- {
-- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-- int status;
--
-- DBG("%s", hdev->name);
--
-- husb->read_urb->dev = husb->udev;
-- if ((status = usb_submit_urb(husb->read_urb)))
-- DBG("read submit failed. %d", status);
-+ int offset = 0, i;
-
-- husb->intr_urb->dev = husb->udev;
-- if ((status = usb_submit_urb(husb->intr_urb)))
-- DBG("interrupt submit failed. %d", status);
-+ BT_DBG("len %d mtu %d", len, mtu);
-
-- hdev->flags |= HCI_RUNNING;
--
-- return 0;
-+ for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
-+ urb->iso_frame_desc[i].offset = offset;
-+ urb->iso_frame_desc[i].length = mtu;
-+ BT_DBG("desc %d offset %d len %d", i, offset, mtu);
-+ }
-+ if (len && i < HCI_MAX_ISOC_FRAMES) {
-+ urb->iso_frame_desc[i].offset = offset;
-+ urb->iso_frame_desc[i].length = len;
-+ BT_DBG("desc %d offset %d len %d", i, offset, len);
-+ i++;
-+ }
-+ urb->number_of_packets = i;
- }
-
--/* Reset device */
--int hci_usb_flush(struct hci_dev *hdev)
-+static int hci_usb_intr_rx_submit(struct hci_usb *husb)
- {
-- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ struct _urb *_urb;
-+ struct urb *urb;
-+ int err, pipe, interval, size;
-+ void *buf;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s", husb->hdev.name);
-
-- /* Drop TX queues */
-- skb_queue_purge(&husb->tx_ctrl_q);
-- skb_queue_purge(&husb->tx_write_q);
-+ size = husb->intr_in_ep->wMaxPacketSize;
-
-- return 0;
-+ buf = kmalloc(size, GFP_ATOMIC);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb) {
-+ kfree(buf);
-+ return -ENOMEM;
-+ }
-+ _urb->type = HCI_EVENT_PKT;
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+
-+ urb = &_urb->urb;
-+ pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress);
-+ interval = husb->intr_in_ep->bInterval;
-+ FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s intr rx submit failed urb %p err %d",
-+ husb->hdev.name, urb, err);
-+ _urb_unlink(_urb);
-+ _urb_free(_urb);
-+ kfree(buf);
-+ }
-+ return err;
- }
-
--/* Close device */
--int hci_usb_close(struct hci_dev *hdev)
-+static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
- {
-- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ struct _urb *_urb;
-+ struct urb *urb;
-+ int err, pipe, size = HCI_MAX_FRAME_SIZE;
-+ void *buf;
-
-- DBG("%s", hdev->name);
-+ buf = kmalloc(size, GFP_ATOMIC);
-+ if (!buf)
-+ return -ENOMEM;
-
-- hdev->flags &= ~HCI_RUNNING;
-- hci_usb_unlink_urbs(husb);
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb) {
-+ kfree(buf);
-+ return -ENOMEM;
-+ }
-+ _urb->type = HCI_ACLDATA_PKT;
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-
-- hci_usb_flush(hdev);
-+ urb = &_urb->urb;
-+ pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress);
-+ FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
-+ urb->transfer_flags = USB_QUEUE_BULK;
-
-- return 0;
-+ BT_DBG("%s urb %p", husb->hdev.name, urb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s bulk rx submit failed urb %p err %d",
-+ husb->hdev.name, urb, err);
-+ _urb_unlink(_urb);
-+ _urb_free(_urb);
-+ kfree(buf);
-+ }
-+ return err;
- }
-
--void hci_usb_ctrl_wakeup(struct hci_usb *husb)
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
- {
-- struct sk_buff *skb;
--
-- if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
-- return;
-+ struct _urb *_urb;
-+ struct urb *urb;
-+ int err, mtu, size;
-+ void *buf;
-
-- DBG("%s", husb->hdev.name);
-+ mtu = husb->isoc_in_ep->wMaxPacketSize;
-+ size = mtu * HCI_MAX_ISOC_FRAMES;
-
-- if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
-- goto done;
-+ buf = kmalloc(size, GFP_ATOMIC);
-+ if (!buf)
-+ return -ENOMEM;
-
-- if (hci_usb_ctrl_msg(husb, skb)){
-- kfree_skb(skb);
-- goto done;
-+ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-+ if (!_urb) {
-+ kfree(buf);
-+ return -ENOMEM;
- }
-+ _urb->type = HCI_SCODATA_PKT;
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-
-- DMP(skb->data, skb->len);
-+ urb = &_urb->urb;
-
-- husb->hdev.stat.byte_tx += skb->len;
-- return;
-+ urb->context = husb;
-+ urb->dev = husb->udev;
-+ urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress);
-+ urb->complete = hci_usb_rx_complete;
-
--done:
-- clear_bit(HCI_TX_CTRL, &husb->tx_state);
-- return;
-+ urb->transfer_buffer_length = size;
-+ urb->transfer_buffer = buf;
-+ urb->transfer_flags = USB_ISO_ASAP;
-+
-+ __fill_isoc_desc(urb, size, mtu);
-+
-+ BT_DBG("%s urb %p", husb->hdev.name, urb);
-+
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s isoc rx submit failed urb %p err %d",
-+ husb->hdev.name, urb, err);
-+ _urb_unlink(_urb);
-+ _urb_free(_urb);
-+ kfree(buf);
-+ }
-+ return err;
- }
-+#endif
-
--void hci_usb_write_wakeup(struct hci_usb *husb)
-+/* Initialize device */
-+static int hci_usb_open(struct hci_dev *hdev)
- {
-- struct sk_buff *skb;
-+ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ int i, err;
-+ unsigned long flags;
-
-- if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
-- return;
-+ BT_DBG("%s", hdev->name);
-
-- DBG("%s", husb->hdev.name);
-+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-
-- if (!(skb = skb_dequeue(&husb->tx_write_q)))
-- goto done;
-+ MOD_INC_USE_COUNT;
-
-- if (hci_usb_write_msg(husb, skb)) {
-- skb_queue_head(&husb->tx_write_q, skb);
-- goto done;
-+ write_lock_irqsave(&husb->completion_lock, flags);
-+
-+ err = hci_usb_intr_rx_submit(husb);
-+ if (!err) {
-+ for (i = 0; i < HCI_MAX_BULK_RX; i++)
-+ hci_usb_bulk_rx_submit(husb);
-+
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ if (husb->isoc_iface)
-+ for (i = 0; i < HCI_MAX_ISOC_RX; i++)
-+ hci_usb_isoc_rx_submit(husb);
-+#endif
-+ } else {
-+ clear_bit(HCI_RUNNING, &hdev->flags);
-+ MOD_DEC_USE_COUNT;
- }
-
-- DMP(skb->data, skb->len);
-+ write_unlock_irqrestore(&husb->completion_lock, flags);
-+ return err;
-+}
-+
-+/* Reset device */
-+static int hci_usb_flush(struct hci_dev *hdev)
-+{
-+ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ int i;
-
-- husb->hdev.stat.byte_tx += skb->len;
-- return;
-+ BT_DBG("%s", hdev->name);
-
--done:
-- clear_bit(HCI_TX_WRITE, &husb->tx_state);
-- return;
-+ for (i=0; i < 4; i++)
-+ skb_queue_purge(&husb->transmit_q[i]);
-+ return 0;
- }
-
--/* Send frames from HCI layer */
--int hci_usb_send_frame(struct sk_buff *skb)
-+static void hci_usb_unlink_urbs(struct hci_usb *husb)
- {
-- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-- struct hci_usb *husb;
-+ int i;
-
-- if (!hdev) {
-- ERR("frame for uknown device (hdev=NULL)");
-- return -ENODEV;
-+ BT_DBG("%s", husb->hdev.name);
-+
-+ for (i=0; i < 4; i++) {
-+ struct _urb *_urb;
-+ struct urb *urb;
-+
-+ /* Kill pending requests */
-+ while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
-+ urb = &_urb->urb;
-+ BT_DBG("%s unlinking _urb %p type %d urb %p",
-+ husb->hdev.name, _urb, _urb->type, urb);
-+ usb_unlink_urb(urb);
-+ _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+ }
-+
-+ /* Release completed requests */
-+ while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
-+ urb = &_urb->urb;
-+ BT_DBG("%s freeing _urb %p type %d urb %p",
-+ husb->hdev.name, _urb, _urb->type, urb);
-+ if (urb->setup_packet)
-+ kfree(urb->setup_packet);
-+ if (urb->transfer_buffer)
-+ kfree(urb->transfer_buffer);
-+ _urb_free(_urb);
-+ }
-+
-+ /* Release reassembly buffers */
-+ if (husb->reassembly[i]) {
-+ kfree_skb(husb->reassembly[i]);
-+ husb->reassembly[i] = NULL;
-+ }
- }
-+}
-
-- if (!(hdev->flags & HCI_RUNNING))
-+/* Close device */
-+static int hci_usb_close(struct hci_dev *hdev)
-+{
-+ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+ unsigned long flags;
-+
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
- return 0;
-
-- husb = (struct hci_usb *) hdev->driver_data;
-+ BT_DBG("%s", hdev->name);
-
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+ write_lock_irqsave(&husb->completion_lock, flags);
-+
-+ hci_usb_unlink_urbs(husb);
-+ hci_usb_flush(hdev);
-
-- switch (skb->pkt_type) {
-- case HCI_COMMAND_PKT:
-- skb_queue_tail(&husb->tx_ctrl_q, skb);
-- hci_usb_ctrl_wakeup(husb);
-- hdev->stat.cmd_tx++;
-- return 0;
--
-- case HCI_ACLDATA_PKT:
-- skb_queue_tail(&husb->tx_write_q, skb);
-- hci_usb_write_wakeup(husb);
-- hdev->stat.acl_tx++;
-- return 0;
--
-- case HCI_SCODATA_PKT:
-- return -EOPNOTSUPP;
-- };
-+ write_unlock_irqrestore(&husb->completion_lock, flags);
-
-+ MOD_DEC_USE_COUNT;
- return 0;
- }
-
--/* ---------- USB ------------- */
--
--static void hci_usb_ctrl(struct urb *urb)
-+static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
- {
-- struct sk_buff *skb = (struct sk_buff *) urb->context;
-- struct hci_dev *hdev;
-- struct hci_usb *husb;
--
-- if (!skb)
-- return;
-- hdev = (struct hci_dev *) skb->dev;
-- husb = (struct hci_usb *) hdev->driver_data;
-+ struct urb *urb = &_urb->urb;
-+ int err;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type);
-+
-+ _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+ err = usb_submit_urb(urb);
-+ if (err) {
-+ BT_ERR("%s tx submit failed urb %p type %d err %d",
-+ husb->hdev.name, urb, _urb->type, err);
-+ _urb_unlink(_urb);
-+ _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+ } else
-+ atomic_inc(__pending_tx(husb, _urb->type));
-+
-+ return err;
-+}
-+
-+static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
-+{
-+ struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+ devrequest *dr;
-+ struct urb *urb;
-+
-+ if (!_urb) {
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb)
-+ return -ENOMEM;
-+ _urb->type = skb->pkt_type;
-+
-+ dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
-+ if (!dr) {
-+ _urb_free(_urb);
-+ return -ENOMEM;
-+ }
-+ } else
-+ dr = (void *) _urb->urb.setup_packet;
-
-- if (urb->status)
-- DBG("%s ctrl status: %d", hdev->name, urb->status);
-+ dr->requesttype = HCI_CTRL_REQ;
-+ dr->request = 0;
-+ dr->index = 0;
-+ dr->value = 0;
-+ dr->length = __cpu_to_le16(skb->len);
-
-- clear_bit(HCI_TX_CTRL, &husb->tx_state);
-- kfree_skb(skb);
-+ urb = &_urb->urb;
-+ FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
-+ (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
-
-- /* Wake up device */
-- hci_usb_ctrl_wakeup(husb);
-+ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-+
-+ _urb->priv = skb;
-+ return __tx_submit(husb, _urb);
- }
-
--static void hci_usb_bulk_write(struct urb *urb)
-+static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
- {
-- struct sk_buff *skb = (struct sk_buff *) urb->context;
-- struct hci_dev *hdev;
-- struct hci_usb *husb;
--
-- if (!skb)
-- return;
-- hdev = (struct hci_dev *) skb->dev;
-- husb = (struct hci_usb *) hdev->driver_data;
-+ struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+ struct urb *urb;
-+ int pipe;
-
-- DBG("%s", hdev->name);
--
-- if (urb->status)
-- DBG("%s bulk write status: %d", hdev->name, urb->status);
-+ if (!_urb) {
-+ _urb = _urb_alloc(0, GFP_ATOMIC);
-+ if (!_urb)
-+ return -ENOMEM;
-+ _urb->type = skb->pkt_type;
-+ }
-
-- clear_bit(HCI_TX_WRITE, &husb->tx_state);
-- kfree_skb(skb);
-+ urb = &_urb->urb;
-+ pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress);
-+ FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
-+ hci_usb_tx_complete, husb);
-+ urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
-
-- /* Wake up device */
-- hci_usb_write_wakeup(husb);
-+ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-
-- return;
-+ _urb->priv = skb;
-+ return __tx_submit(husb, _urb);
- }
-
--static void hci_usb_intr(struct urb *urb)
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
- {
-- struct hci_usb *husb = (struct hci_usb *) urb->context;
-- unsigned char *data = urb->transfer_buffer;
-- register int count = urb->actual_length;
-- register struct sk_buff *skb = husb->intr_skb;
-- hci_event_hdr *eh;
-- register int len;
-+ struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+ struct urb *urb;
-+
-+ if (!_urb) {
-+ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-+ if (!_urb)
-+ return -ENOMEM;
-+ _urb->type = skb->pkt_type;
-+ }
-
-- if (!husb)
-- return;
-+ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-
-- DBG("%s count %d", husb->hdev.name, count);
-+ urb = &_urb->urb;
-+
-+ urb->context = husb;
-+ urb->dev = husb->udev;
-+ urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress);
-+ urb->complete = hci_usb_tx_complete;
-+ urb->transfer_flags = USB_ISO_ASAP;
-
-- if (urb->status || !count) {
-- DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
-- return;
-- }
-+ urb->transfer_buffer = skb->data;
-+ urb->transfer_buffer_length = skb->len;
-+
-+ __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize);
-
-- /* Do we really have to handle continuations here ? */
-- if (!skb) {
-- /* New frame */
-- if (count < HCI_EVENT_HDR_SIZE) {
-- DBG("%s bad frame len %d", husb->hdev.name, count);
-- return;
-- }
-+ _urb->priv = skb;
-+ return __tx_submit(husb, _urb);
-+}
-+#endif
-+
-+static void hci_usb_tx_process(struct hci_usb *husb)
-+{
-+ struct sk_buff_head *q;
-+ struct sk_buff *skb;
-
-- eh = (hci_event_hdr *) data;
-- len = eh->plen + HCI_EVENT_HDR_SIZE;
-+ BT_DBG("%s", husb->hdev.name);
-
-- if (count > len) {
-- DBG("%s corrupted frame, len %d", husb->hdev.name, count);
-- return;
-+ do {
-+ clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
-+
-+ /* Process command queue */
-+ q = __transmit_q(husb, HCI_COMMAND_PKT);
-+ if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
-+ (skb = skb_dequeue(q))) {
-+ if (hci_usb_send_ctrl(husb, skb) < 0)
-+ skb_queue_head(q, skb);
- }
-
-- /* Allocate skb */
-- if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
-- ERR("Can't allocate mem for new packet");
-- return;
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ /* Process SCO queue */
-+ q = __transmit_q(husb, HCI_SCODATA_PKT);
-+ if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
-+ (skb = skb_dequeue(q))) {
-+ if (hci_usb_send_isoc(husb, skb) < 0)
-+ skb_queue_head(q, skb);
-+ }
-+#endif
-+
-+ /* Process ACL queue */
-+ q = __transmit_q(husb, HCI_ACLDATA_PKT);
-+ while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
-+ (skb = skb_dequeue(q))) {
-+ if (hci_usb_send_bulk(husb, skb) < 0) {
-+ skb_queue_head(q, skb);
-+ break;
-+ }
- }
-- skb->dev = (void *) &husb->hdev;
-- skb->pkt_type = HCI_EVENT_PKT;
-+ } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
-+}
-
-- husb->intr_skb = skb;
-- husb->intr_count = len;
-- } else {
-- /* Continuation */
-- if (count > husb->intr_count) {
-- ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
-+static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
-+{
-+ /* Serialize TX queue processing to avoid data reordering */
-+ if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
-+ hci_usb_tx_process(husb);
-+ clear_bit(HCI_USB_TX_PROCESS, &husb->state);
-+ } else
-+ set_bit(HCI_USB_TX_WAKEUP, &husb->state);
-+}
-
-- kfree_skb(skb);
-- husb->intr_skb = NULL;
-- husb->intr_count = 0;
-- return;
-- }
-+/* Send frames from HCI layer */
-+static int hci_usb_send_frame(struct sk_buff *skb)
-+{
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-+ struct hci_usb *husb;
-+
-+ if (!hdev) {
-+ BT_ERR("frame for uknown device (hdev=NULL)");
-+ return -ENODEV;
- }
-
-- memcpy(skb_put(skb, count), data, count);
-- husb->intr_count -= count;
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return -EBUSY;
-
-- DMP(data, count);
-+ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-- if (!husb->intr_count) {
-- /* Got complete frame */
-+ husb = (struct hci_usb *) hdev->driver_data;
-
-- husb->hdev.stat.byte_rx += skb->len;
-- hci_recv_frame(skb);
-+ switch (skb->pkt_type) {
-+ case HCI_COMMAND_PKT:
-+ hdev->stat.cmd_tx++;
-+ break;
-+
-+ case HCI_ACLDATA_PKT:
-+ hdev->stat.acl_tx++;
-+ break;
-+
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ case HCI_SCODATA_PKT:
-+ hdev->stat.sco_tx++;
-+ break;
-+#endif
-
-- husb->intr_skb = NULL;
-+ default:
-+ kfree_skb(skb);
-+ return 0;
- }
-+
-+ read_lock(&husb->completion_lock);
-+
-+ skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
-+ hci_usb_tx_wakeup(husb);
-+
-+ read_unlock(&husb->completion_lock);
-+ return 0;
- }
-
--static void hci_usb_bulk_read(struct urb *urb)
-+static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
- {
-- struct hci_usb *husb = (struct hci_usb *) urb->context;
-- unsigned char *data = urb->transfer_buffer;
-- int count = urb->actual_length, status;
-- struct sk_buff *skb;
-- hci_acl_hdr *ah;
-- register __u16 dlen;
--
-- if (!husb)
-- return;
-+ BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count);
-
-- DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
-+ husb->hdev.stat.byte_rx += count;
-
-- if (urb->status) {
-- /* Do not re-submit URB on critical errors */
-- switch (urb->status) {
-- case -ENOENT:
-- return;
-- default:
-- goto resubmit;
-- };
-- }
-- if (!count)
-- goto resubmit;
-+ while (count) {
-+ struct sk_buff *skb = __reassembly(husb, type);
-+ struct { int expect; } *scb;
-+ int len = 0;
-+
-+ if (!skb) {
-+ /* Start of the frame */
-+
-+ switch (type) {
-+ case HCI_EVENT_PKT:
-+ if (count >= HCI_EVENT_HDR_SIZE) {
-+ hci_event_hdr *h = data;
-+ len = HCI_EVENT_HDR_SIZE + h->plen;
-+ } else
-+ return -EILSEQ;
-+ break;
-
-- DMP(data, count);
-+ case HCI_ACLDATA_PKT:
-+ if (count >= HCI_ACL_HDR_SIZE) {
-+ hci_acl_hdr *h = data;
-+ len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
-+ } else
-+ return -EILSEQ;
-+ break;
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ case HCI_SCODATA_PKT:
-+ if (count >= HCI_SCO_HDR_SIZE) {
-+ hci_sco_hdr *h = data;
-+ len = HCI_SCO_HDR_SIZE + h->dlen;
-+ } else
-+ return -EILSEQ;
-+ break;
-+#endif
-+ }
-+ BT_DBG("new packet len %d", len);
-+
-+ skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s no memory for the packet", husb->hdev.name);
-+ return -ENOMEM;
-+ }
-+ skb->dev = (void *) &husb->hdev;
-+ skb->pkt_type = type;
-+
-+ __reassembly(husb, type) = skb;
-+
-+ scb = (void *) skb->cb;
-+ scb->expect = len;
-+ } else {
-+ /* Continuation */
-+ scb = (void *) skb->cb;
-+ len = scb->expect;
-+ }
-
-- ah = (hci_acl_hdr *) data;
-- dlen = le16_to_cpu(ah->dlen);
-+ len = min(len, count);
-+
-+ memcpy(skb_put(skb, len), data, len);
-+
-+ scb->expect -= len;
-+ if (!scb->expect) {
-+ /* Complete frame */
-+ __reassembly(husb, type) = NULL;
-+ hci_recv_frame(skb);
-+ }
-
-- /* Verify frame len and completeness */
-- if ((count - HCI_ACL_HDR_SIZE) != dlen) {
-- ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
-- goto resubmit;
-+ count -= len; data += len;
- }
-+ return 0;
-+}
-
-- /* Allocate packet */
-- if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
-- ERR("Can't allocate mem for new packet");
-- goto resubmit;
-- }
-+static void hci_usb_rx_complete(struct urb *urb)
-+{
-+ struct _urb *_urb = container_of(urb, struct _urb, urb);
-+ struct hci_usb *husb = (void *) urb->context;
-+ struct hci_dev *hdev = &husb->hdev;
-+ int err, count = urb->actual_length;
-
-- memcpy(skb_put(skb, count), data, count);
-- skb->dev = (void *) &husb->hdev;
-- skb->pkt_type = HCI_ACLDATA_PKT;
-+ BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
-+ _urb->type, urb->status, count, urb->transfer_flags);
-
-- husb->hdev.stat.byte_rx += skb->len;
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return;
-
-- hci_recv_frame(skb);
-+ read_lock(&husb->completion_lock);
-
--resubmit:
-- husb->read_urb->dev = husb->udev;
-- if ((status = usb_submit_urb(husb->read_urb)))
-- DBG("%s read URB submit failed %d", husb->hdev.name, status);
-+ if (urb->status || !count)
-+ goto resubmit;
-+
-+ if (_urb->type == HCI_SCODATA_PKT) {
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ int i;
-+ for (i=0; i < urb->number_of_packets; i++) {
-+ BT_DBG("desc %d status %d offset %d len %d", i,
-+ urb->iso_frame_desc[i].status,
-+ urb->iso_frame_desc[i].offset,
-+ urb->iso_frame_desc[i].actual_length);
-+
-+ if (!urb->iso_frame_desc[i].status)
-+ __recv_frame(husb, _urb->type,
-+ urb->transfer_buffer + urb->iso_frame_desc[i].offset,
-+ urb->iso_frame_desc[i].actual_length);
-+ }
-+#else
-+ ;
-+#endif
-+ } else {
-+ err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
-+ if (err < 0) {
-+ BT_ERR("%s corrupted packet: type %d count %d",
-+ husb->hdev.name, _urb->type, count);
-+ hdev->stat.err_rx++;
-+ }
-+ }
-
-- DBG("%s read URB re-submited", husb->hdev.name);
-+resubmit:
-+ if (_urb->type != HCI_EVENT_PKT) {
-+ urb->dev = husb->udev;
-+ err = usb_submit_urb(urb);
-+ BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
-+ _urb->type, err);
-+ }
-+ read_unlock(&husb->completion_lock);
- }
-
--static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
-+static void hci_usb_tx_complete(struct urb *urb)
- {
-- struct urb *urb = husb->ctrl_urb;
-- devrequest *dr = &husb->dev_req;
-- int pipe, status;
-+ struct _urb *_urb = container_of(urb, struct _urb, urb);
-+ struct hci_usb *husb = (void *) urb->context;
-+ struct hci_dev *hdev = &husb->hdev;
-
-- DBG("%s len %d", husb->hdev.name, skb->len);
-+ BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
-+ urb->status, urb->transfer_flags);
-
-- pipe = usb_sndctrlpipe(husb->udev, 0);
-+ atomic_dec(__pending_tx(husb, _urb->type));
-
-- dr->requesttype = HCI_CTRL_REQ;
-- dr->request = 0;
-- dr->index = 0;
-- dr->value = 0;
-- dr->length = cpu_to_le16(skb->len);
-+ urb->transfer_buffer = NULL;
-+ kfree_skb((struct sk_buff *) _urb->priv);
-
-- FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
-- hci_usb_ctrl, skb);
--
-- if ((status = usb_submit_urb(urb))) {
-- DBG("%s control URB submit failed %d", husb->hdev.name, status);
-- return status;
-- }
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
-+ return;
-
-- return 0;
--}
-+ if (!urb->status)
-+ hdev->stat.byte_tx += urb->transfer_buffer_length;
-+ else
-+ hdev->stat.err_tx++;
-
--static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
--{
-- struct urb *urb = husb->write_urb;
-- int pipe, status;
-+ read_lock(&husb->completion_lock);
-
-- DBG("%s len %d", husb->hdev.name, skb->len);
-+ _urb_unlink(_urb);
-+ _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-
-- pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
-+ hci_usb_tx_wakeup(husb);
-+
-+ read_unlock(&husb->completion_lock);
-+}
-
-- FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
-- hci_usb_bulk_write, skb);
-- urb->transfer_flags |= USB_QUEUE_BULK;
-+static void hci_usb_destruct(struct hci_dev *hdev)
-+{
-+ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-
-- if ((status = usb_submit_urb(urb))) {
-- DBG("%s write URB submit failed %d", husb->hdev.name, status);
-- return status;
-- }
-+ BT_DBG("%s", hdev->name);
-
-- return 0;
-+ kfree(husb);
- }
-
--static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
- {
-- struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
-+ struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];
-+ struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];
- struct usb_interface_descriptor *uif;
- struct usb_endpoint_descriptor *ep;
-+ struct usb_interface *iface, *isoc_iface;
- struct hci_usb *husb;
- struct hci_dev *hdev;
-- int i, size, pipe;
-- __u8 * buf;
-+ int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
-
-- DBG("udev %p ifnum %d", udev, ifnum);
--
-- /* Check device signature */
-- if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) ||
-- (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
-- (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
-- return NULL;
--
-- MOD_INC_USE_COUNT;
-+ BT_DBG("udev %p ifnum %d", udev, ifnum);
-
-- uif = &udev->actconfig->interface[ifnum].altsetting[0];
-+ iface = &udev->actconfig->interface[0];
-
-- if (uif->bNumEndpoints != 3) {
-- DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
-- MOD_DEC_USE_COUNT;
-+ /* Check our black list */
-+ if (usb_match_id(udev, iface, ignore_ids))
- return NULL;
-- }
-
-- bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
-+ /* Check number of endpoints */
-+ if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
-+ return NULL;
-
-+ memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
-+ memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
-+ memset(bulk_in_ep, 0, sizeof(bulk_in_ep));
-+ memset(isoc_in_ep, 0, sizeof(isoc_in_ep));
-+ memset(intr_in_ep, 0, sizeof(intr_in_ep));
-+
-+ size = 0;
-+ isoc_iface = NULL;
-+ isoc_alts = isoc_ifnum = 0;
-+
- /* Find endpoints that we need */
-- for ( i = 0; i < uif->bNumEndpoints; ++i) {
-- ep = &uif->endpoint[i];
-
-- switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-- case USB_ENDPOINT_XFER_BULK:
-- if (ep->bEndpointAddress & USB_DIR_IN)
-- bulk_in_ep = ep;
-- else
-- bulk_out_ep = ep;
-- break;
-+ ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
-+ for (i = 0; i < ifn; i++) {
-+ iface = &udev->actconfig->interface[i];
-+ for (a = 0; a < iface->num_altsetting; a++) {
-+ uif = &iface->altsetting[a];
-+ for (e = 0; e < uif->bNumEndpoints; e++) {
-+ ep = &uif->endpoint[e];
-+
-+ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-+ case USB_ENDPOINT_XFER_INT:
-+ if (ep->bEndpointAddress & USB_DIR_IN)
-+ intr_in_ep[i] = ep;
-+ break;
-+
-+ case USB_ENDPOINT_XFER_BULK:
-+ if (ep->bEndpointAddress & USB_DIR_IN)
-+ bulk_in_ep[i] = ep;
-+ else
-+ bulk_out_ep[i] = ep;
-+ break;
-+
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ case USB_ENDPOINT_XFER_ISOC:
-+ if (ep->wMaxPacketSize < size || a > 2)
-+ break;
-+ size = ep->wMaxPacketSize;
-+
-+ isoc_iface = iface;
-+ isoc_alts = a;
-+ isoc_ifnum = i;
-+
-+ if (ep->bEndpointAddress & USB_DIR_IN)
-+ isoc_in_ep[i] = ep;
-+ else
-+ isoc_out_ep[i] = ep;
-+ break;
-+#endif
-+ }
-+ }
-+ }
-+ }
-
-- case USB_ENDPOINT_XFER_INT:
-- intr_in_ep = ep;
-- break;
-- };
-+ if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
-+ BT_DBG("Bulk endpoints not found");
-+ goto done;
- }
-
-- if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
-- DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
-- MOD_DEC_USE_COUNT;
-- return NULL;
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
-+ BT_DBG("Isoc endpoints not found");
-+ isoc_iface = NULL;
- }
-+#endif
-
- if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
-- ERR("Can't allocate: control structure");
-- MOD_DEC_USE_COUNT;
-- return NULL;
-+ BT_ERR("Can't allocate: control structure");
-+ goto done;
- }
-
- memset(husb, 0, sizeof(struct hci_usb));
-
- husb->udev = udev;
-- husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
--
-- if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: control URB");
-- goto probe_error;
-- }
--
-- if (!(husb->write_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: write URB");
-- goto probe_error;
-- }
--
-- if (!(husb->read_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: read URB");
-- goto probe_error;
-- }
--
-- ep = bulk_in_ep;
-- pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
-- size = HCI_MAX_FRAME_SIZE;
--
-- if (!(buf = kmalloc(size, GFP_KERNEL))) {
-- ERR("Can't allocate: read buffer");
-- goto probe_error;
-- }
--
-- FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
-- husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
--
-- ep = intr_in_ep;
-- pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
-- size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
--
-- if (!(husb->intr_urb = usb_alloc_urb(0))) {
-- ERR("Can't allocate: interrupt URB");
-- goto probe_error;
-+ husb->bulk_out_ep = bulk_out_ep[0];
-+ husb->bulk_in_ep = bulk_in_ep[0];
-+ husb->intr_in_ep = intr_in_ep[0];
-+
-+#ifdef CONFIG_BLUEZ_USB_SCO
-+ if (isoc_iface) {
-+ BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
-+ if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
-+ BT_ERR("Can't set isoc interface settings");
-+ isoc_iface = NULL;
-+ }
-+ usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
-+ husb->isoc_iface = isoc_iface;
-+ husb->isoc_in_ep = isoc_in_ep[isoc_ifnum];
-+ husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
- }
-+#endif
-+
-+ husb->completion_lock = RW_LOCK_UNLOCKED;
-
-- if (!(buf = kmalloc(size, GFP_KERNEL))) {
-- ERR("Can't allocate: interrupt buffer");
-- goto probe_error;
-+ for (i = 0; i < 4; i++) {
-+ skb_queue_head_init(&husb->transmit_q[i]);
-+ _urb_queue_init(&husb->pending_q[i]);
-+ _urb_queue_init(&husb->completed_q[i]);
- }
-
-- FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
--
-- skb_queue_head_init(&husb->tx_ctrl_q);
-- skb_queue_head_init(&husb->tx_write_q);
--
- /* Initialize and register HCI device */
- hdev = &husb->hdev;
-
-- hdev->type = HCI_USB;
-+ hdev->type = HCI_USB;
- hdev->driver_data = husb;
-
- hdev->open = hci_usb_open;
- hdev->close = hci_usb_close;
- hdev->flush = hci_usb_flush;
-- hdev->send = hci_usb_send_frame;
-+ hdev->send = hci_usb_send_frame;
-+ hdev->destruct = hci_usb_destruct;
-
- if (hci_register_dev(hdev) < 0) {
-- ERR("Can't register HCI device %s", hdev->name);
-+ BT_ERR("Can't register HCI device");
- goto probe_error;
- }
-
- return husb;
-
- probe_error:
-- hci_usb_free_bufs(husb);
- kfree(husb);
-- MOD_DEC_USE_COUNT;
-+
-+done:
- return NULL;
- }
-
-@@ -626,38 +930,34 @@
- if (!husb)
- return;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s", hdev->name);
-
- hci_usb_close(hdev);
-
-- if (hci_unregister_dev(hdev) < 0) {
-- ERR("Can't unregister HCI device %s", hdev->name);
-- }
-+ if (husb->isoc_iface)
-+ usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
-
-- hci_usb_free_bufs(husb);
-- kfree(husb);
--
-- MOD_DEC_USE_COUNT;
-+ if (hci_unregister_dev(hdev) < 0)
-+ BT_ERR("Can't unregister HCI device %s", hdev->name);
- }
-
--static struct usb_driver hci_usb_driver =
--{
-+static struct usb_driver hci_usb_driver = {
- name: "hci_usb",
- probe: hci_usb_probe,
- disconnect: hci_usb_disconnect,
-- id_table: usb_bluetooth_ids,
-+ id_table: bluetooth_ids,
- };
-
- int hci_usb_init(void)
- {
- int err;
-
-- INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
- if ((err = usb_register(&hci_usb_driver)) < 0)
-- ERR("Failed to register HCI USB driver");
-+ BT_ERR("Failed to register HCI USB driver");
-
- return err;
- }
-diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.h linux-2.4.18-mh9/drivers/bluetooth/hci_usb.h
---- linux-2.4.18/drivers/bluetooth/hci_usb.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_usb.h Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,139 @@
-+/*
-+ HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifdef __KERNEL__
-+
-+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-+#define HCI_DEV_CLASS 0xe0 /* Wireless class */
-+#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */
-+#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */
-+
-+#define HCI_CTRL_REQ 0x20
-+
-+#define HCI_MAX_IFACE_NUM 3
-+
-+#define HCI_MAX_BULK_TX 4
-+#define HCI_MAX_BULK_RX 1
-+
-+#define HCI_MAX_ISOC_RX 2
-+#define HCI_MAX_ISOC_TX 2
-+
-+#define HCI_MAX_ISOC_FRAMES 10
-+
-+struct _urb_queue {
-+ struct list_head head;
-+ spinlock_t lock;
-+};
-+
-+struct _urb {
-+ struct list_head list;
-+ struct _urb_queue *queue;
-+ int type;
-+ void *priv;
-+ struct urb urb;
-+};
-+
-+struct _urb *_urb_alloc(int isoc, int gfp);
-+
-+static inline void _urb_free(struct _urb *_urb)
-+{
-+ kfree(_urb);
-+}
-+
-+static inline void _urb_queue_init(struct _urb_queue *q)
-+{
-+ INIT_LIST_HEAD(&q->head);
-+ spin_lock_init(&q->lock);
-+}
-+
-+static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
-+{
-+ unsigned long flags;
-+ spin_lock_irqsave(&q->lock, flags);
-+ list_add(&_urb->list, &q->head); _urb->queue = q;
-+ spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
-+{
-+ unsigned long flags;
-+ spin_lock_irqsave(&q->lock, flags);
-+ list_add_tail(&_urb->list, &q->head); _urb->queue = q;
-+ spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+static inline void _urb_unlink(struct _urb *_urb)
-+{
-+ struct _urb_queue *q = _urb->queue;
-+ unsigned long flags;
-+ if (q) {
-+ spin_lock_irqsave(&q->lock, flags);
-+ list_del(&_urb->list); _urb->queue = NULL;
-+ spin_unlock_irqrestore(&q->lock, flags);
-+ }
-+}
-+
-+struct _urb *_urb_dequeue(struct _urb_queue *q);
-+
-+#ifndef container_of
-+#define container_of(ptr, type, member) ({ \
-+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-+ (type *)( (char *)__mptr - offsetof(type,member) );})
-+#endif
-+
-+struct hci_usb {
-+ struct hci_dev hdev;
-+
-+ unsigned long state;
-+
-+ struct usb_device *udev;
-+
-+ struct usb_endpoint_descriptor *bulk_in_ep;
-+ struct usb_endpoint_descriptor *bulk_out_ep;
-+ struct usb_endpoint_descriptor *intr_in_ep;
-+
-+ struct usb_interface *isoc_iface;
-+ struct usb_endpoint_descriptor *isoc_out_ep;
-+ struct usb_endpoint_descriptor *isoc_in_ep;
-+
-+ struct sk_buff_head transmit_q[4];
-+ struct sk_buff *reassembly[4]; // Reassembly buffers
-+
-+ rwlock_t completion_lock;
-+
-+ atomic_t pending_tx[4]; // Number of pending requests
-+ struct _urb_queue pending_q[4]; // Pending requests
-+ struct _urb_queue completed_q[4]; // Completed requests
-+};
-+
-+/* States */
-+#define HCI_USB_TX_PROCESS 1
-+#define HCI_USB_TX_WAKEUP 2
-+
-+#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.c linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.c
---- linux-2.4.18/drivers/bluetooth/hci_vhci.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.c Mon Aug 25 18:38:10 2003
-@@ -25,9 +25,9 @@
- /*
- * BlueZ HCI virtual device driver.
- *
-- * $Id$
-+ * $Id$
- */
--#define VERSION "1.0"
-+#define VERSION "1.1"
-
- #include <linux/config.h>
- #include <linux/module.h>
-@@ -49,43 +49,56 @@
- #include <asm/uaccess.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_vhci.h>
-+#include "hci_vhci.h"
-
- /* HCI device part */
-
--int hci_vhci_open(struct hci_dev *hdev)
-+static int hci_vhci_open(struct hci_dev *hdev)
- {
-- hdev->flags |= HCI_RUNNING;
-+ set_bit(HCI_RUNNING, &hdev->flags);
- return 0;
- }
-
--int hci_vhci_flush(struct hci_dev *hdev)
-+static int hci_vhci_flush(struct hci_dev *hdev)
- {
- struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
- skb_queue_purge(&hci_vhci->readq);
- return 0;
- }
-
--int hci_vhci_close(struct hci_dev *hdev)
-+static int hci_vhci_close(struct hci_dev *hdev)
- {
-- hdev->flags &= ~HCI_RUNNING;
-+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+ return 0;
-+
- hci_vhci_flush(hdev);
- return 0;
- }
-
--int hci_vhci_send_frame(struct sk_buff *skb)
-+static void hci_vhci_destruct(struct hci_dev *hdev)
-+{
-+ struct hci_vhci_struct *vhci;
-+
-+ if (!hdev) return;
-+
-+ vhci = (struct hci_vhci_struct *) hdev->driver_data;
-+ kfree(vhci);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static int hci_vhci_send_frame(struct sk_buff *skb)
- {
- struct hci_dev* hdev = (struct hci_dev *) skb->dev;
- struct hci_vhci_struct *hci_vhci;
-
- if (!hdev) {
-- ERR("Frame for uknown device (hdev=NULL)");
-+ BT_ERR("Frame for uknown device (hdev=NULL)");
- return -ENODEV;
- }
-
-- if (!(hdev->flags & HCI_RUNNING))
-+ if (!test_bit(HCI_RUNNING, &hdev->flags))
- return -EBUSY;
-
- hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
-@@ -188,7 +201,7 @@
-
- add_wait_queue(&hci_vhci->read_wait, &wait);
- while (count) {
-- current->state = TASK_INTERRUPTIBLE;
-+ set_current_state(TASK_INTERRUPTIBLE);
-
- /* Read frames from device queue */
- if (!(skb = skb_dequeue(&hci_vhci->readq))) {
-@@ -214,8 +227,7 @@
- kfree_skb(skb);
- break;
- }
--
-- current->state = TASK_RUNNING;
-+ set_current_state(TASK_RUNNING);
- remove_wait_queue(&hci_vhci->read_wait, &wait);
-
- return ret;
-@@ -270,11 +282,13 @@
- hdev->close = hci_vhci_close;
- hdev->flush = hci_vhci_flush;
- hdev->send = hci_vhci_send_frame;
-+ hdev->destruct = hci_vhci_destruct;
-
- if (hci_register_dev(hdev) < 0) {
- kfree(hci_vhci);
- return -EBUSY;
- }
-+ MOD_INC_USE_COUNT;
-
- file->private_data = hci_vhci;
- return 0;
-@@ -285,12 +299,10 @@
- struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-
- if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
-- ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
-+ BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
- }
-
-- kfree(hci_vhci);
- file->private_data = NULL;
--
- return 0;
- }
-
-@@ -315,12 +327,12 @@
-
- int __init hci_vhci_init(void)
- {
-- INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
- if (misc_register(&hci_vhci_miscdev)) {
-- ERR("Can't register misc device %d\n", VHCI_MINOR);
-+ BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
- return -EIO;
- }
-
-@@ -337,4 +349,4 @@
-
- MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
- MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
--MODULE_LICENSE("GPL");
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.h linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.h
---- linux-2.4.18/drivers/bluetooth/hci_vhci.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.h Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,50 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __HCI_VHCI_H
-+#define __HCI_VHCI_H
-+
-+#ifdef __KERNEL__
-+
-+struct hci_vhci_struct {
-+ struct hci_dev hdev;
-+ __u32 flags;
-+ wait_queue_head_t read_wait;
-+ struct sk_buff_head readq;
-+ struct fasync_struct *fasync;
-+};
-+
-+/* VHCI device flags */
-+#define VHCI_FASYNC 0x0010
-+
-+#endif /* __KERNEL__ */
-+
-+#define VHCI_DEV "/dev/vhci"
-+#define VHCI_MINOR 250
-+
-+#endif /* __HCI_VHCI_H */
-diff -urN linux-2.4.18/drivers/char/pcmcia/serial_cs.c linux-2.4.18-mh9/drivers/char/pcmcia/serial_cs.c
---- linux-2.4.18/drivers/char/pcmcia/serial_cs.c Fri Dec 21 18:41:54 2001
-+++ linux-2.4.18-mh9/drivers/char/pcmcia/serial_cs.c Mon Aug 25 18:38:10 2003
-@@ -2,7 +2,7 @@
-
- A driver for PCMCIA serial devices
-
-- serial_cs.c 1.128 2001/10/18 12:18:35
-+ serial_cs.c 1.138 2002/10/25 06:24:52
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
-@@ -28,7 +28,7 @@
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the MPL or the GPL.
--
-+
- ======================================================================*/
-
- #include <linux/module.h>
-@@ -69,14 +69,14 @@
- static int irq_list[4] = { -1 };
- MODULE_PARM(irq_list, "1-4i");
-
--/* Enable the speaker? */
--INT_MODULE_PARM(do_sound, 1);
-+INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */
-+INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */
-
- #ifdef PCMCIA_DEBUG
- INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
- #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
- static char *version =
--"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
-+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
- #else
- #define DEBUG(n, args...)
- #endif
-@@ -95,6 +95,7 @@
- { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
-+ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
-@@ -148,7 +149,7 @@
- client_reg_t client_reg;
- dev_link_t *link;
- int i, ret;
--
-+
- DEBUG(0, "serial_attach()\n");
-
- /* Create new serial device */
-@@ -160,7 +161,7 @@
- link->release.function = &serial_release;
- link->release.data = (u_long)link;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-- link->io.NumPorts1 = 8;
-+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
-@@ -169,13 +170,12 @@
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
- link->conf.Attributes = CONF_ENABLE_IRQ;
-- link->conf.Vcc = 50;
- if (do_sound) {
- link->conf.Attributes |= CONF_ENABLE_SPKR;
- link->conf.Status = CCSR_AUDIO_ENA;
- }
- link->conf.IntType = INT_MEMORY_AND_IO;
--
-+
- /* Register with Card Services */
- link->next = dev_list;
- dev_list = link;
-@@ -194,7 +194,7 @@
- serial_detach(link);
- return NULL;
- }
--
-+
- return link;
- } /* serial_attach */
-
-@@ -214,7 +214,7 @@
- int ret;
-
- DEBUG(0, "serial_detach(0x%p)\n", link);
--
-+
- /* Locate device structure */
- for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
- if (*linkp == link) break;
-@@ -224,17 +224,17 @@
- del_timer(&link->release);
- if (link->state & DEV_CONFIG)
- serial_release((u_long)link);
--
-+
- if (link->handle) {
- ret = CardServices(DeregisterClient, link->handle);
- if (ret != CS_SUCCESS)
- cs_error(link->handle, DeregisterClient, ret);
- }
--
-+
- /* Unlink device structure, free bits */
- *linkp = link->next;
- kfree(info);
--
-+
- } /* serial_detach */
-
- /*====================================================================*/
-@@ -243,18 +243,20 @@
- {
- struct serial_struct serial;
- int line;
--
-+
- memset(&serial, 0, sizeof(serial));
- serial.port = port;
- serial.irq = irq;
- serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
-+ if (buggy_uart)
-+ serial.flags |= ASYNC_BUGGY_UART;
- line = register_serial(&serial);
- if (line < 0) {
- printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
- " irq %d failed\n", (u_long)serial.port, serial.irq);
- return -1;
- }
--
-+
- info->line[info->ndev] = line;
- sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
- info->node[info->ndev].major = TTY_MAJOR;
-@@ -262,7 +264,7 @@
- if (info->ndev > 0)
- info->node[info->ndev-1].next = &info->node[info->ndev];
- info->ndev++;
--
-+
- return 0;
- }
-
-@@ -313,7 +315,10 @@
- return setup_serial(info, port, config.AssignedIRQ);
- }
- link->conf.Vcc = config.Vcc;
--
-+
-+ link->io.NumPorts1 = 8;
-+ link->io.NumPorts2 = 0;
-+
- /* First pass: look for a config entry that looks normal. */
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-@@ -340,7 +345,7 @@
- i = next_tuple(handle, &tuple, &parse);
- }
- }
--
-+
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
-@@ -352,8 +357,7 @@
- for (j = 0; j < 5; j++) {
- link->io.BasePort1 = base[j];
- link->io.IOAddrLines = base[j] ? 16 : 3;
-- i = CardServices(RequestIO, link->handle,
-- &link->io);
-+ i = CardServices(RequestIO, link->handle, &link->io);
- if (i == CS_SUCCESS) goto found_port;
- }
- }
-@@ -365,7 +369,7 @@
- cs_error(link->handle, RequestIO, i);
- return -1;
- }
--
-+
- i = CardServices(RequestIRQ, link->handle, &link->irq);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIRQ, i);
-@@ -390,8 +394,12 @@
- u_char buf[256];
- cisparse_t parse;
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+ config_info_t config;
- int i, base2 = 0;
-
-+ CardServices(GetConfigurationInfo, handle, &config);
-+ link->conf.Vcc = config.Vcc;
-+
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
-@@ -433,12 +441,12 @@
- i = next_tuple(handle, &tuple, &parse);
- }
- }
--
-+
- if (i != CS_SUCCESS) {
-- cs_error(link->handle, RequestIO, i);
-- return -1;
-+ /* At worst, try to configure as a single port */
-+ return simple_config(link);
- }
--
-+
- i = CardServices(RequestIRQ, link->handle, &link->irq);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIRQ, i);
-@@ -454,14 +462,27 @@
- cs_error(link->handle, RequestConfiguration, i);
- return -1;
- }
--
-+
-+ /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-+ 8 registers are for the UART, the others are extra registers */
-+ if (info->manfid == MANFID_OXSEMI) {
-+ if (cf->index == 1 || cf->index == 3) {
-+ setup_serial(info, base2, link->irq.AssignedIRQ);
-+ outb(12,link->io.BasePort1+1);
-+ } else {
-+ setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
-+ outb(12,base2+1);
-+ }
-+ return 0;
-+ }
-+
- setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
- /* The Nokia cards are not really multiport cards */
- if (info->manfid == MANFID_NOKIA)
- return 0;
- for (i = 0; i < info->multi-1; i++)
- setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
--
-+
- return 0;
- }
-
-@@ -487,7 +508,7 @@
- int i, last_ret, last_fn;
-
- DEBUG(0, "serial_config(0x%p)\n", link);
--
-+
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
-@@ -500,7 +521,7 @@
- }
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
--
-+
- /* Configure card */
- link->state |= DEV_CONFIG;
-
-@@ -508,8 +529,8 @@
- tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
- tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
- info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
--
-- /* Is this a multiport card? */
-+
-+ /* Scan list of known multiport card ID's */
- tuple.DesiredTuple = CISTPL_MANFID;
- if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
- info->manfid = le16_to_cpu(buf[0]);
-@@ -537,15 +558,15 @@
- info->multi = 2;
- }
- }
--
-+
- if (info->multi > 1)
- multi_config(link);
- else
- simple_config(link);
--
-+
- if (info->ndev == 0)
- goto failed;
--
-+
- if (info->manfid == MANFID_IBM) {
- conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
- CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
-@@ -562,6 +583,7 @@
- cs_error(link->handle, last_fn, last_ret);
- failed:
- serial_release((u_long)link);
-+ link->state &= ~DEV_CONFIG_PENDING;
-
- } /* serial_config */
-
-@@ -569,7 +591,7 @@
-
- After a card is removed, serial_release() will unregister the net
- device, and release the PCMCIA configuration.
--
-+
- ======================================================================*/
-
- void serial_release(u_long arg)
-@@ -577,7 +599,7 @@
- dev_link_t *link = (dev_link_t *)arg;
- serial_info_t *info = link->priv;
- int i;
--
-+
- DEBUG(0, "serial_release(0x%p)\n", link);
-
- for (i = 0; i < info->ndev; i++) {
-@@ -590,7 +612,7 @@
- CardServices(ReleaseIO, link->handle, &link->io);
- CardServices(ReleaseIRQ, link->handle, &link->irq);
- }
--
-+
- link->state &= ~DEV_CONFIG;
-
- } /* serial_release */
-@@ -601,7 +623,7 @@
- stuff to run after an event is received. A CARD_REMOVAL event
- also sets some flags to discourage the serial drivers from
- talking to the ports.
--
-+
- ======================================================================*/
-
- static int serial_event(event_t event, int priority,
-@@ -609,9 +631,9 @@
- {
- dev_link_t *link = args->client_data;
- serial_info_t *info = link->priv;
--
-+
- DEBUG(1, "serial_event(0x%06x)\n", event);
--
-+
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- link->state &= ~DEV_PRESENT;
-@@ -650,7 +672,7 @@
- if (serv.Revision != CS_RELEASE_CODE) {
- printk(KERN_NOTICE "serial_cs: Card Services release "
- "does not match!\n");
-- return -1;
-+ return -EINVAL;
- }
- register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
- return 0;
-diff -urN linux-2.4.18/drivers/usb/Config.in linux-2.4.18-mh9/drivers/usb/Config.in
---- linux-2.4.18/drivers/usb/Config.in Mon Feb 25 20:38:07 2002
-+++ linux-2.4.18-mh9/drivers/usb/Config.in Mon Aug 25 18:38:10 2003
-@@ -31,7 +31,13 @@
-
- comment 'USB Device Class drivers'
- dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
--dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+ if [ "$CONFIG_BLUEZ" = "n" ]; then
-+ dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
-+ else
-+ comment ' USB Bluetooth can only be used with disabled Bluetooth subsystem'
-+ fi
-+fi
- if [ "$CONFIG_SCSI" = "n" ]; then
- comment ' SCSI support is needed for USB Storage'
- fi
-diff -urN linux-2.4.18/include/linux/firmware.h linux-2.4.18-mh9/include/linux/firmware.h
---- linux-2.4.18/include/linux/firmware.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/include/linux/firmware.h Mon Aug 25 18:38:10 2003
-@@ -0,0 +1,20 @@
-+#ifndef _LINUX_FIRMWARE_H
-+#define _LINUX_FIRMWARE_H
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#define FIRMWARE_NAME_MAX 30
-+struct firmware {
-+ size_t size;
-+ u8 *data;
-+};
-+int request_firmware (const struct firmware **fw, const char *name,
-+ const char *device);
-+int request_firmware_nowait (
-+ struct module *module,
-+ const char *name, const char *device, void *context,
-+ void (*cont)(const struct firmware *fw, void *context));
-+/* On 2.5 'device' is 'struct device *' */
-+
-+void release_firmware (const struct firmware *fw);
-+void register_firmware (const char *name, const u8 *data, size_t size);
-+#endif
-diff -urN linux-2.4.18/include/linux/kernel.h linux-2.4.18-mh9/include/linux/kernel.h
---- linux-2.4.18/include/linux/kernel.h Mon Feb 25 20:38:13 2002
-+++ linux-2.4.18-mh9/include/linux/kernel.h Mon Aug 25 18:38:11 2003
-@@ -11,6 +11,7 @@
- #include <linux/linkage.h>
- #include <linux/stddef.h>
- #include <linux/types.h>
-+#include <linux/compiler.h>
-
- /* Optimization barrier */
- /* The "volatile" is due to gcc bugs */
-@@ -181,4 +182,6 @@
- char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
- };
-
--#endif
-+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
-+
-+#endif /* _LINUX_KERNEL_H */
-diff -urN linux-2.4.18/include/net/bluetooth/bluetooth.h linux-2.4.18-mh9/include/net/bluetooth/bluetooth.h
---- linux-2.4.18/include/net/bluetooth/bluetooth.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/bluetooth.h Mon Aug 25 18:38:11 2003
-@@ -23,7 +23,7 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __BLUETOOTH_H
-@@ -31,17 +31,63 @@
-
- #include <asm/types.h>
- #include <asm/byteorder.h>
-+#include <linux/poll.h>
-+#include <net/sock.h>
-
- #ifndef AF_BLUETOOTH
- #define AF_BLUETOOTH 31
- #define PF_BLUETOOTH AF_BLUETOOTH
- #endif
-
-+/* Reserv for core and drivers use */
-+#define BLUEZ_SKB_RESERVE 8
-+
-+#ifndef MIN
-+#define MIN(a,b) ((a) < (b) ? (a) : (b))
-+#endif
-+
- #define BTPROTO_L2CAP 0
- #define BTPROTO_HCI 1
-+#define BTPROTO_SCO 2
-+#define BTPROTO_RFCOMM 3
-+#define BTPROTO_BNEP 4
-+#define BTPROTO_CMTP 5
-
- #define SOL_HCI 0
- #define SOL_L2CAP 6
-+#define SOL_SCO 17
-+#define SOL_RFCOMM 18
-+
-+/* Debugging */
-+#ifdef CONFIG_BLUEZ_DEBUG
-+
-+#define HCI_CORE_DEBUG 1
-+#define HCI_SOCK_DEBUG 1
-+#define HCI_UART_DEBUG 1
-+#define HCI_USB_DEBUG 1
-+//#define HCI_DATA_DUMP 1
-+
-+#define L2CAP_DEBUG 1
-+#define SCO_DEBUG 1
-+#define AF_BLUETOOTH_DEBUG 1
-+
-+#endif /* CONFIG_BLUEZ_DEBUG */
-+
-+extern void bluez_dump(char *pref, __u8 *buf, int count);
-+
-+#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95
-+#define __func__ __FUNCTION__
-+#endif
-+
-+#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
-+#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
-+#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
-+
-+#ifdef HCI_DATA_DUMP
-+#define BT_DMP(buf, len) bluez_dump(__func__, buf, len)
-+#else
-+#define BT_DMP(D...)
-+#endif
-
- /* Connection and socket states */
- enum {
-@@ -50,6 +96,7 @@
- BT_BOUND,
- BT_LISTEN,
- BT_CONNECT,
-+ BT_CONNECT2,
- BT_CONFIG,
- BT_DISCONN,
- BT_CLOSED
-@@ -66,7 +113,8 @@
- __u8 b[6];
- } __attribute__((packed)) bdaddr_t;
-
--#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000")
-+#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
-
- /* Copy, swap, convert BD Address */
- static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
-@@ -82,6 +130,91 @@
- char *batostr(bdaddr_t *ba);
- bdaddr_t *strtoba(char *str);
-
-+/* Common socket structures and functions */
-+
-+#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo)
-+#define bluez_sk(pi) ((struct sock *) \
-+ ((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo)))
-+
-+struct bluez_pinfo {
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+
-+ struct list_head accept_q;
-+ struct sock *parent;
-+};
-+
-+struct bluez_sock_list {
-+ struct sock *head;
-+ rwlock_t lock;
-+};
-+
-+int bluez_sock_register(int proto, struct net_proto_family *ops);
-+int bluez_sock_unregister(int proto);
-+void bluez_sock_init(struct socket *sock, struct sock *sk);
-+void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
-+void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
-+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
-+uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
-+
-+void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
-+struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
-+
-+/* Skb helpers */
-+struct bluez_skb_cb {
-+ int incomming;
-+};
-+#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb))
-+
-+static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
-+{
-+ struct sk_buff *skb;
-+
-+ if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
-+ skb_reserve(skb, BLUEZ_SKB_RESERVE);
-+ bluez_cb(skb)->incomming = 0;
-+ }
-+ return skb;
-+}
-+
-+static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len,
-+ int nb, int *err)
-+{
-+ struct sk_buff *skb;
-+
-+ if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
-+ skb_reserve(skb, BLUEZ_SKB_RESERVE);
-+ bluez_cb(skb)->incomming = 0;
-+ }
-+
-+ return skb;
-+}
-+
-+static inline int skb_frags_no(struct sk_buff *skb)
-+{
-+ register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
-+ register int n = 1;
-+
-+ for (; frag; frag=frag->next, n++);
-+ return n;
-+}
-+
-+int hci_core_init(void);
-+int hci_core_cleanup(void);
-+int hci_sock_init(void);
-+int hci_sock_cleanup(void);
-+
- int bterr(__u16 code);
-+
-+#ifndef MODULE_LICENSE
-+#define MODULE_LICENSE(x)
-+#endif
-+
-+#ifndef list_for_each_safe
-+#define list_for_each_safe(pos, n, head) \
-+ for (pos = (head)->next, n = pos->next; pos != (head); \
-+ pos = n, n = pos->next)
-+#endif
-
- #endif /* __BLUETOOTH_H */
-diff -urN linux-2.4.18/include/net/bluetooth/bluez.h linux-2.4.18-mh9/include/net/bluetooth/bluez.h
---- linux-2.4.18/include/net/bluetooth/bluez.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/bluez.h Thu Jan 1 01:00:00 1970
-@@ -1,124 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef __IF_BLUEZ_H
--#define __IF_BLUEZ_H
--
--#include <net/sock.h>
--
--#define BLUEZ_MAX_PROTO 2
--
--/* Reserv for core and drivers use */
--#define BLUEZ_SKB_RESERVE 8
--
--#ifndef MIN
--#define MIN(a,b) ((a) < (b) ? (a) : (b))
--#endif
--
--/* Debugging */
--#ifdef BLUEZ_DEBUG
--
--#define HCI_CORE_DEBUG 1
--#define HCI_SOCK_DEBUG 1
--#define HCI_UART_DEBUG 1
--#define HCI_USB_DEBUG 1
--//#define HCI_DATA_DUMP 1
--
--#define L2CAP_DEBUG 1
--
--#endif /* BLUEZ_DEBUG */
--
--extern void bluez_dump(char *pref, __u8 *buf, int count);
--
--#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
--#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
--#define ERR(fmt, arg...) printk(KERN_ERR __FUNCTION__ ": " fmt "\n" , ## arg)
--
--#ifdef HCI_DATA_DUMP
--#define DMP(buf, len) bluez_dump(__FUNCTION__, buf, len)
--#else
--#define DMP(D...)
--#endif
--
--/* ----- Sockets ------ */
--struct bluez_sock_list {
-- struct sock *head;
-- rwlock_t lock;
--};
--
--extern int bluez_sock_register(int proto, struct net_proto_family *ops);
--extern int bluez_sock_unregister(int proto);
--
--extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
--extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
--
--/* ----- SKB helpers ----- */
--struct bluez_skb_cb {
-- int incomming;
--};
--#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb))
--
--static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
--{
-- struct sk_buff *skb;
--
-- if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
-- skb_reserve(skb, BLUEZ_SKB_RESERVE);
-- bluez_cb(skb)->incomming = 0;
-- }
-- return skb;
--}
--
--static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len,
-- int nb, int *err)
--{
-- struct sk_buff *skb;
--
-- if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
-- skb_reserve(skb, BLUEZ_SKB_RESERVE);
-- bluez_cb(skb)->incomming = 0;
-- }
--
-- return skb;
--}
--
--static inline int skb_frags_no(struct sk_buff *skb)
--{
-- register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
-- register int n = 1;
--
-- for (; frag; frag=frag->next, n++);
-- return n;
--}
--
--extern int hci_core_init(void);
--extern int hci_core_cleanup(void);
--extern int hci_sock_init(void);
--extern int hci_sock_cleanup(void);
--
--#endif /* __IF_BLUEZ_H */
-diff -urN linux-2.4.18/include/net/bluetooth/hci.h linux-2.4.18-mh9/include/net/bluetooth/hci.h
---- linux-2.4.18/include/net/bluetooth/hci.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/hci.h Mon Aug 25 18:38:12 2003
-@@ -23,59 +23,80 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __HCI_H
- #define __HCI_H
-
--#include <asm/byteorder.h>
--
--#define HCI_MAX_DEV 8
--#define HCI_MAX_FRAME_SIZE 2048
-+#define HCI_MAX_ACL_SIZE 1024
-+#define HCI_MAX_SCO_SIZE 255
-+#define HCI_MAX_EVENT_SIZE 260
-+#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
-
- /* HCI dev events */
- #define HCI_DEV_REG 1
- #define HCI_DEV_UNREG 2
- #define HCI_DEV_UP 3
- #define HCI_DEV_DOWN 4
-+#define HCI_DEV_SUSPEND 5
-+#define HCI_DEV_RESUME 6
-+
-+/* HCI notify events */
-+#define HCI_NOTIFY_CONN_ADD 1
-+#define HCI_NOTIFY_CONN_DEL 2
-+#define HCI_NOTIFY_VOICE_SETTING 3
-
- /* HCI device types */
--#define HCI_UART 0
-+#define HCI_VHCI 0
- #define HCI_USB 1
--#define HCI_VHCI 2
--
--/* HCI device modes */
--#define HCI_NORMAL 0x0001
--#define HCI_RAW 0x0002
--#define HCI_MODE_MASK (HCI_NORMAL | HCI_RAW)
--#define HCI_SOCK 0x1000
--
--/* HCI device states */
--#define HCI_INIT 0x0010
--#define HCI_UP 0x0020
--#define HCI_RUNNING 0x0040
-+#define HCI_PCCARD 2
-+#define HCI_UART 3
-+#define HCI_RS232 4
-+#define HCI_PCI 5
-
- /* HCI device flags */
--#define HCI_PSCAN 0x0100
--#define HCI_ISCAN 0x0200
--#define HCI_AUTH 0x0400
-+enum {
-+ HCI_UP,
-+ HCI_INIT,
-+ HCI_RUNNING,
-+
-+ HCI_PSCAN,
-+ HCI_ISCAN,
-+ HCI_AUTH,
-+ HCI_ENCRYPT,
-+ HCI_INQUIRY,
-+
-+ HCI_RAW
-+};
-
--/* HCI Ioctl defines */
-+/* HCI ioctl defines */
- #define HCIDEVUP _IOW('H', 201, int)
- #define HCIDEVDOWN _IOW('H', 202, int)
- #define HCIDEVRESET _IOW('H', 203, int)
--#define HCIRESETSTAT _IOW('H', 204, int)
--#define HCIGETINFO _IOR('H', 205, int)
--#define HCIGETDEVLIST _IOR('H', 206, int)
--#define HCISETRAW _IOW('H', 207, int)
--#define HCISETSCAN _IOW('H', 208, int)
--#define HCISETAUTH _IOW('H', 209, int)
--#define HCIINQUIRY _IOR('H', 210, int)
--#define HCISETPTYPE _IOW('H', 211, int)
-+#define HCIDEVRESTAT _IOW('H', 204, int)
-+
-+#define HCIGETDEVLIST _IOR('H', 210, int)
-+#define HCIGETDEVINFO _IOR('H', 211, int)
- #define HCIGETCONNLIST _IOR('H', 212, int)
-+#define HCIGETCONNINFO _IOR('H', 213, int)
-
--#ifndef __NO_HCI_DEFS
-+#define HCISETRAW _IOW('H', 220, int)
-+#define HCISETSCAN _IOW('H', 221, int)
-+#define HCISETAUTH _IOW('H', 222, int)
-+#define HCISETENCRYPT _IOW('H', 223, int)
-+#define HCISETPTYPE _IOW('H', 224, int)
-+#define HCISETLINKPOL _IOW('H', 225, int)
-+#define HCISETLINKMODE _IOW('H', 226, int)
-+#define HCISETACLMTU _IOW('H', 227, int)
-+#define HCISETSCOMTU _IOW('H', 228, int)
-+
-+#define HCIINQUIRY _IOR('H', 240, int)
-+
-+/* HCI timeouts */
-+#define HCI_CONN_TIMEOUT (HZ * 40)
-+#define HCI_DISCONN_TIMEOUT (HZ * 2)
-+#define HCI_CONN_IDLE_TIMEOUT (HZ * 60)
-
- /* HCI Packet types */
- #define HCI_COMMAND_PKT 0x01
-@@ -92,11 +113,18 @@
- #define HCI_DH3 0x0800
- #define HCI_DH5 0x8000
-
-+#define HCI_HV1 0x0020
-+#define HCI_HV2 0x0040
-+#define HCI_HV3 0x0080
-+
-+#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3)
-+#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK)
-+
- /* ACL flags */
--#define ACL_CONT 0x0001
--#define ACL_START 0x0002
--#define ACL_ACTIVE_BCAST 0x0010
--#define ACL_PICO_BCAST 0x0020
-+#define ACL_CONT 0x01
-+#define ACL_START 0x02
-+#define ACL_ACTIVE_BCAST 0x04
-+#define ACL_PICO_BCAST 0x08
-
- /* Baseband links */
- #define SCO_LINK 0x00
-@@ -125,6 +153,20 @@
- #define LMP_PSCHEME 0x02
- #define LMP_PCONTROL 0x04
-
-+/* Link policies */
-+#define HCI_LP_RSWITCH 0x0001
-+#define HCI_LP_HOLD 0x0002
-+#define HCI_LP_SNIFF 0x0004
-+#define HCI_LP_PARK 0x0008
-+
-+/* Link mode */
-+#define HCI_LM_ACCEPT 0x8000
-+#define HCI_LM_MASTER 0x0001
-+#define HCI_LM_AUTH 0x0002
-+#define HCI_LM_ENCRYPT 0x0004
-+#define HCI_LM_TRUSTED 0x0008
-+#define HCI_LM_RELIABLE 0x0010
-+
- /* ----- HCI Commands ----- */
- /* OGF & OCF values */
-
-@@ -137,9 +179,10 @@
- __u8 hci_ver;
- __u16 hci_rev;
- __u8 lmp_ver;
-- __u16 man_name;
-- __u16 lmp_sub;
-+ __u16 manufacturer;
-+ __u16 lmp_subver;
- } __attribute__ ((packed)) read_local_version_rp;
-+#define READ_LOCAL_VERSION_RP_SIZE 9
-
- #define OCF_READ_LOCAL_FEATURES 0x0003
- typedef struct {
-@@ -165,18 +208,24 @@
- /* Host Controller and Baseband */
- #define OGF_HOST_CTL 0x03
- #define OCF_RESET 0x0003
-+#define OCF_READ_AUTH_ENABLE 0x001F
- #define OCF_WRITE_AUTH_ENABLE 0x0020
-- #define AUTH_DISABLED 0x00
-- #define AUTH_ENABLED 0x01
-+ #define AUTH_DISABLED 0x00
-+ #define AUTH_ENABLED 0x01
-+
-+#define OCF_READ_ENCRYPT_MODE 0x0021
-+#define OCF_WRITE_ENCRYPT_MODE 0x0022
-+ #define ENCRYPT_DISABLED 0x00
-+ #define ENCRYPT_P2P 0x01
-+ #define ENCRYPT_BOTH 0x02
-
- #define OCF_WRITE_CA_TIMEOUT 0x0016
- #define OCF_WRITE_PG_TIMEOUT 0x0018
-
- #define OCF_WRITE_SCAN_ENABLE 0x001A
-- #define SCANS_DISABLED 0x00
-- #define IS_ENA_PS_DIS 0x01
-- #define IS_DIS_PS_ENA 0x02
-- #define IS_ENA_PS_ENA 0x03
-+ #define SCAN_DISABLED 0x00
-+ #define SCAN_INQUIRY 0x01
-+ #define SCAN_PAGE 0x02
-
- #define OCF_SET_EVENT_FLT 0x0005
- typedef struct {
-@@ -226,9 +275,31 @@
- } __attribute__ ((packed)) write_class_of_dev_cp;
- #define WRITE_CLASS_OF_DEV_CP_SIZE 3
-
-+#define OCF_READ_VOICE_SETTING 0x0025
-+typedef struct {
-+ __u8 status;
-+ __u16 voice_setting;
-+} __attribute__ ((packed)) read_voice_setting_rp;
-+#define READ_VOICE_SETTING_RP_SIZE 3
-+
-+#define OCF_WRITE_VOICE_SETTING 0x0026
-+typedef struct {
-+ __u16 voice_setting;
-+} __attribute__ ((packed)) write_voice_setting_cp;
-+#define WRITE_VOICE_SETTING_CP_SIZE 2
-+
-+#define OCF_HOST_BUFFER_SIZE 0x0033
-+typedef struct {
-+ __u16 acl_mtu;
-+ __u8 sco_mtu;
-+ __u16 acl_max_pkt;
-+ __u16 sco_max_pkt;
-+} __attribute__ ((packed)) host_buffer_size_cp;
-+#define HOST_BUFFER_SIZE_CP_SIZE 7
-+
- /* Link Control */
- #define OGF_LINK_CTL 0x01
--#define OCF_CREATE_CONN 0x0005
-+#define OCF_CREATE_CONN 0x0005
- typedef struct {
- bdaddr_t bdaddr;
- __u16 pkt_type;
-@@ -246,6 +317,13 @@
- } __attribute__ ((packed)) accept_conn_req_cp;
- #define ACCEPT_CONN_REQ_CP_SIZE 7
-
-+#define OCF_REJECT_CONN_REQ 0x000a
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 reason;
-+} __attribute__ ((packed)) reject_conn_req_cp;
-+#define REJECT_CONN_REQ_CP_SIZE 7
-+
- #define OCF_DISCONNECT 0x0006
- typedef struct {
- __u16 handle;
-@@ -253,17 +331,142 @@
- } __attribute__ ((packed)) disconnect_cp;
- #define DISCONNECT_CP_SIZE 3
-
-+#define OCF_ADD_SCO 0x0007
-+typedef struct {
-+ __u16 handle;
-+ __u16 pkt_type;
-+} __attribute__ ((packed)) add_sco_cp;
-+#define ADD_SCO_CP_SIZE 4
-+
- #define OCF_INQUIRY 0x0001
- typedef struct {
- __u8 lap[3];
-- __u8 lenght;
-+ __u8 length;
- __u8 num_rsp;
- } __attribute__ ((packed)) inquiry_cp;
- #define INQUIRY_CP_SIZE 5
-
--#define OGF_LINK_POLICY 0x02 /* Link Policy */
-+typedef struct {
-+ __u8 status;
-+ bdaddr_t bdaddr;
-+} __attribute__ ((packed)) status_bdaddr_rp;
-+#define STATUS_BDADDR_RP_SIZE 7
-+
-+#define OCF_INQUIRY_CANCEL 0x0002
-+
-+#define OCF_LINK_KEY_REPLY 0x000B
-+#define OCF_LINK_KEY_NEG_REPLY 0x000C
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 link_key[16];
-+} __attribute__ ((packed)) link_key_reply_cp;
-+#define LINK_KEY_REPLY_CP_SIZE 22
-+
-+#define OCF_PIN_CODE_REPLY 0x000D
-+#define OCF_PIN_CODE_NEG_REPLY 0x000E
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 pin_len;
-+ __u8 pin_code[16];
-+} __attribute__ ((packed)) pin_code_reply_cp;
-+#define PIN_CODE_REPLY_CP_SIZE 23
-+
-+#define OCF_CHANGE_CONN_PTYPE 0x000F
-+typedef struct {
-+ __u16 handle;
-+ __u16 pkt_type;
-+} __attribute__ ((packed)) change_conn_ptype_cp;
-+#define CHANGE_CONN_PTYPE_CP_SIZE 4
-+
-+#define OCF_AUTH_REQUESTED 0x0011
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) auth_requested_cp;
-+#define AUTH_REQUESTED_CP_SIZE 2
-+
-+#define OCF_SET_CONN_ENCRYPT 0x0013
-+typedef struct {
-+ __u16 handle;
-+ __u8 encrypt;
-+} __attribute__ ((packed)) set_conn_encrypt_cp;
-+#define SET_CONN_ENCRYPT_CP_SIZE 3
-+
-+#define OCF_REMOTE_NAME_REQ 0x0019
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 pscan_rep_mode;
-+ __u8 pscan_mode;
-+ __u16 clock_offset;
-+} __attribute__ ((packed)) remote_name_req_cp;
-+#define REMOTE_NAME_REQ_CP_SIZE 10
-+
-+#define OCF_READ_REMOTE_FEATURES 0x001B
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) read_remote_features_cp;
-+#define READ_REMOTE_FEATURES_CP_SIZE 2
-+
-+#define OCF_READ_REMOTE_VERSION 0x001D
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) read_remote_version_cp;
-+#define READ_REMOTE_VERSION_CP_SIZE 2
-+
-+/* Link Policy */
-+#define OGF_LINK_POLICY 0x02
-+#define OCF_ROLE_DISCOVERY 0x0009
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) role_discovery_cp;
-+#define ROLE_DISCOVERY_CP_SIZE 2
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 role;
-+} __attribute__ ((packed)) role_discovery_rp;
-+#define ROLE_DISCOVERY_RP_SIZE 4
-
--/* --------- HCI Events --------- */
-+#define OCF_READ_LINK_POLICY 0x000C
-+typedef struct {
-+ __u16 handle;
-+} __attribute__ ((packed)) read_link_policy_cp;
-+#define READ_LINK_POLICY_CP_SIZE 2
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u16 policy;
-+} __attribute__ ((packed)) read_link_policy_rp;
-+#define READ_LINK_POLICY_RP_SIZE 5
-+
-+#define OCF_SWITCH_ROLE 0x000B
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 role;
-+} __attribute__ ((packed)) switch_role_cp;
-+#define SWITCH_ROLE_CP_SIZE 7
-+
-+#define OCF_WRITE_LINK_POLICY 0x000D
-+typedef struct {
-+ __u16 handle;
-+ __u16 policy;
-+} __attribute__ ((packed)) write_link_policy_cp;
-+#define WRITE_LINK_POLICY_CP_SIZE 4
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+} __attribute__ ((packed)) write_link_policy_rp;
-+#define WRITE_LINK_POLICY_RP_SIZE 3
-+
-+/* Status params */
-+#define OGF_STATUS_PARAM 0x05
-+
-+/* Testing commands */
-+#define OGF_TESTING_CMD 0x3e
-+
-+/* Vendor specific commands */
-+#define OGF_VENDOR_CMD 0x3f
-+
-+/* ---- HCI Events ---- */
- #define EVT_INQUIRY_COMPLETE 0x01
-
- #define EVT_INQUIRY_RESULT 0x02
-@@ -272,7 +475,7 @@
- __u8 pscan_rep_mode;
- __u8 pscan_period_mode;
- __u8 pscan_mode;
-- __u8 class[3];
-+ __u8 dev_class[3];
- __u16 clock_offset;
- } __attribute__ ((packed)) inquiry_info;
- #define INQUIRY_INFO_SIZE 14
-@@ -303,6 +506,44 @@
- } __attribute__ ((packed)) evt_disconn_complete;
- #define EVT_DISCONN_COMPLETE_SIZE 4
-
-+#define EVT_AUTH_COMPLETE 0x06
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+} __attribute__ ((packed)) evt_auth_complete;
-+#define EVT_AUTH_COMPLETE_SIZE 3
-+
-+#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07
-+typedef struct {
-+ __u8 status;
-+ bdaddr_t bdaddr;
-+ __u8 name[248];
-+} __attribute__ ((packed)) evt_remote_name_req_complete;
-+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
-+
-+#define EVT_ENCRYPT_CHANGE 0x08
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 encrypt;
-+} __attribute__ ((packed)) evt_encrypt_change;
-+#define EVT_ENCRYPT_CHANGE_SIZE 5
-+
-+#define EVT_QOS_SETUP_COMPLETE 0x0D
-+typedef struct {
-+ __u8 service_type;
-+ __u32 token_rate;
-+ __u32 peak_bandwidth;
-+ __u32 latency;
-+ __u32 delay_variation;
-+} __attribute__ ((packed)) hci_qos;
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ hci_qos qos;
-+} __attribute__ ((packed)) evt_qos_setup_complete;
-+#define EVT_QOS_SETUP_COMPLETE_SIZE 20
-+
- #define EVT_CMD_COMPLETE 0x0e
- typedef struct {
- __u8 ncmd;
-@@ -321,16 +562,78 @@
- #define EVT_NUM_COMP_PKTS 0x13
- typedef struct {
- __u8 num_hndl;
-- /* variable lenght part */
-+ /* variable length part */
- } __attribute__ ((packed)) evt_num_comp_pkts;
- #define EVT_NUM_COMP_PKTS_SIZE 1
-
--#define EVT_HCI_DEV_EVENT 0xfd
-+#define EVT_ROLE_CHANGE 0x12
-+typedef struct {
-+ __u8 status;
-+ bdaddr_t bdaddr;
-+ __u8 role;
-+} __attribute__ ((packed)) evt_role_change;
-+#define EVT_ROLE_CHANGE_SIZE 8
-+
-+#define EVT_PIN_CODE_REQ 0x16
-+typedef struct {
-+ bdaddr_t bdaddr;
-+} __attribute__ ((packed)) evt_pin_code_req;
-+#define EVT_PIN_CODE_REQ_SIZE 6
-+
-+#define EVT_LINK_KEY_REQ 0x17
-+typedef struct {
-+ bdaddr_t bdaddr;
-+} __attribute__ ((packed)) evt_link_key_req;
-+#define EVT_LINK_KEY_REQ_SIZE 6
-+
-+#define EVT_LINK_KEY_NOTIFY 0x18
-+typedef struct {
-+ bdaddr_t bdaddr;
-+ __u8 link_key[16];
-+ __u8 key_type;
-+} __attribute__ ((packed)) evt_link_key_notify;
-+#define EVT_LINK_KEY_NOTIFY_SIZE 23
-+
-+#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 features[8];
-+} __attribute__ ((packed)) evt_read_remote_features_complete;
-+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
-+
-+#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C
-+typedef struct {
-+ __u8 status;
-+ __u16 handle;
-+ __u8 lmp_ver;
-+ __u16 manufacturer;
-+ __u16 lmp_subver;
-+} __attribute__ ((packed)) evt_read_remote_version_complete;
-+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
-+
-+/* Internal events generated by BlueZ stack */
-+#define EVT_STACK_INTERNAL 0xfd
-+typedef struct {
-+ __u16 type;
-+ __u8 data[0];
-+} __attribute__ ((packed)) evt_stack_internal;
-+#define EVT_STACK_INTERNAL_SIZE 2
-+
-+#define EVT_SI_DEVICE 0x01
-+typedef struct {
-+ __u16 event;
-+ __u16 dev_id;
-+} __attribute__ ((packed)) evt_si_device;
-+#define EVT_SI_DEVICE_SIZE 4
-+
-+#define EVT_SI_SECURITY 0x02
- typedef struct {
- __u16 event;
-- __u16 param;
--} __attribute__ ((packed)) evt_hci_dev_event;
--#define EVT_HCI_DEV_EVENT_SIZE 4
-+ __u16 proto;
-+ __u16 subproto;
-+ __u8 incomming;
-+} __attribute__ ((packed)) evt_si_security;
-
- /* -------- HCI Packet structures -------- */
- #define HCI_TYPE_LEN 1
-@@ -369,14 +672,14 @@
- #define acl_handle(h) (h & 0x0fff)
- #define acl_flags(h) (h >> 12)
-
--#endif /* _NO_HCI_DEFS */
--
- /* HCI Socket options */
--#define HCI_DATA_DIR 0x0001
--#define HCI_FILTER 0x0002
-+#define HCI_DATA_DIR 1
-+#define HCI_FILTER 2
-+#define HCI_TIME_STAMP 3
-
- /* HCI CMSG flags */
- #define HCI_CMSG_DIR 0x0001
-+#define HCI_CMSG_TSTAMP 0x0002
-
- struct sockaddr_hci {
- sa_family_t hci_family;
-@@ -387,27 +690,29 @@
- struct hci_filter {
- __u32 type_mask;
- __u32 event_mask[2];
-+ __u16 opcode;
- };
-
--struct hci_dev_req {
-- __u16 dev_id;
-- __u32 dev_opt;
--};
--
--struct hci_dev_list_req {
-- __u16 dev_num;
-- struct hci_dev_req dev_req[0]; /* hci_dev_req structures */
--};
--
--struct hci_inquiry_req {
-- __u16 dev_id;
-- __u16 flags;
-- __u8 lap[3];
-- __u8 length;
-- __u8 num_rsp;
--};
--#define IREQ_CACHE_FLUSH 0x0001
-+#define HCI_FLT_TYPE_BITS 31
-+#define HCI_FLT_EVENT_BITS 63
-+#define HCI_FLT_OGF_BITS 63
-+#define HCI_FLT_OCF_BITS 127
-+
-+#if BITS_PER_LONG == 64
-+static inline void hci_set_bit(int nr, void *addr)
-+{
-+ *((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
-+}
-+static inline int hci_test_bit(int nr, void *addr)
-+{
-+ return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
-+}
-+#else
-+#define hci_set_bit set_bit
-+#define hci_test_bit test_bit
-+#endif
-
-+/* Ioctl requests structures */
- struct hci_dev_stats {
- __u32 err_rx;
- __u32 err_tx;
-@@ -433,11 +738,13 @@
- __u8 features[8];
-
- __u32 pkt_type;
-+ __u32 link_policy;
-+ __u32 link_mode;
-
- __u16 acl_mtu;
-- __u16 acl_max;
-+ __u16 acl_pkts;
- __u16 sco_mtu;
-- __u16 sco_max;
-+ __u16 sco_pkts;
-
- struct hci_dev_stats stat;
- };
-@@ -445,12 +752,48 @@
- struct hci_conn_info {
- __u16 handle;
- bdaddr_t bdaddr;
-+ __u8 type;
-+ __u8 out;
-+ __u16 state;
-+ __u32 link_mode;
-+};
-+
-+struct hci_dev_req {
-+ __u16 dev_id;
-+ __u32 dev_opt;
-+};
-+
-+struct hci_dev_list_req {
-+ __u16 dev_num;
-+ struct hci_dev_req dev_req[0]; /* hci_dev_req structures */
- };
-
- struct hci_conn_list_req {
- __u16 dev_id;
- __u16 conn_num;
- struct hci_conn_info conn_info[0];
-+};
-+
-+struct hci_conn_info_req {
-+ bdaddr_t bdaddr;
-+ __u8 type;
-+ struct hci_conn_info conn_info[0];
-+};
-+
-+struct hci_inquiry_req {
-+ __u16 dev_id;
-+ __u16 flags;
-+ __u8 lap[3];
-+ __u8 length;
-+ __u8 num_rsp;
-+};
-+#define IREQ_CACHE_FLUSH 0x0001
-+
-+struct hci_remotename_req {
-+ __u16 dev_id;
-+ __u16 flags;
-+ bdaddr_t bdaddr;
-+ __u8 name[248];
- };
-
- #endif /* __HCI_H */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_core.h linux-2.4.18-mh9/include/net/bluetooth/hci_core.h
---- linux-2.4.18/include/net/bluetooth/hci_core.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/hci_core.h Mon Aug 25 18:38:12 2003
-@@ -23,7 +23,7 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __HCI_CORE_H
-@@ -32,14 +32,12 @@
- #include <net/bluetooth/hci.h>
-
- /* HCI upper protocols */
--#define HCI_MAX_PROTO 1
- #define HCI_PROTO_L2CAP 0
-+#define HCI_PROTO_SCO 1
-
- #define HCI_INIT_TIMEOUT (HZ * 10)
-
--/* ----- Inquiry cache ----- */
--#define INQUIRY_CACHE_AGE_MAX (HZ*5) // 5 seconds
--#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds
-+/* HCI Core structures */
-
- struct inquiry_entry {
- struct inquiry_entry *next;
-@@ -53,111 +51,182 @@
- struct inquiry_entry *list;
- };
-
--static inline void inquiry_cache_init(struct inquiry_cache *cache)
--{
-- spin_lock_init(&cache->lock);
-- cache->list = NULL;
--}
-+struct conn_hash {
-+ struct list_head list;
-+ spinlock_t lock;
-+ unsigned int num;
-+};
-
--static inline void inquiry_cache_lock(struct inquiry_cache *cache)
--{
-- spin_lock(&cache->lock);
--}
-+struct hci_dev {
-+ struct list_head list;
-+ spinlock_t lock;
-+ atomic_t refcnt;
-
--static inline void inquiry_cache_unlock(struct inquiry_cache *cache)
--{
-- spin_unlock(&cache->lock);
--}
-+ char name[8];
-+ unsigned long flags;
-+ __u16 id;
-+ __u8 type;
-+ bdaddr_t bdaddr;
-+ __u8 features[8];
-+ __u16 voice_setting;
-
--static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache)
--{
-- spin_lock_bh(&cache->lock);
--}
-+ __u16 pkt_type;
-+ __u16 link_policy;
-+ __u16 link_mode;
-
--static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
--{
-- spin_unlock_bh(&cache->lock);
--}
-+ atomic_t cmd_cnt;
-+ unsigned int acl_cnt;
-+ unsigned int sco_cnt;
-
--static inline long inquiry_cache_age(struct inquiry_cache *cache)
--{
-- return jiffies - cache->timestamp;
--}
-+ unsigned int acl_mtu;
-+ unsigned int sco_mtu;
-+ unsigned int acl_pkts;
-+ unsigned int sco_pkts;
-
--static inline long inquiry_entry_age(struct inquiry_entry *e)
--{
-- return jiffies - e->timestamp;
--}
--extern void inquiry_cache_flush(struct inquiry_cache *cache);
-+ unsigned long cmd_last_tx;
-+ unsigned long acl_last_tx;
-+ unsigned long sco_last_tx;
-+
-+ struct tasklet_struct cmd_task;
-+ struct tasklet_struct rx_task;
-+ struct tasklet_struct tx_task;
-
--struct hci_dev;
-+ struct sk_buff_head rx_q;
-+ struct sk_buff_head raw_q;
-+ struct sk_buff_head cmd_q;
-+
-+ struct sk_buff *sent_cmd;
-+
-+ struct semaphore req_lock;
-+ wait_queue_head_t req_wait_q;
-+ __u32 req_status;
-+ __u32 req_result;
-+
-+ struct inquiry_cache inq_cache;
-+ struct conn_hash conn_hash;
-+
-+ struct hci_dev_stats stat;
-+
-+ void *driver_data;
-+ void *core_data;
-+
-+ atomic_t promisc;
-+
-+ int (*open)(struct hci_dev *hdev);
-+ int (*close)(struct hci_dev *hdev);
-+ int (*flush)(struct hci_dev *hdev);
-+ int (*send)(struct sk_buff *skb);
-+ void (*destruct)(struct hci_dev *hdev);
-+ void (*notify)(struct hci_dev *hdev, unsigned int evt, unsigned long arg);
-+ int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
-+};
-
--/* ----- HCI Connections ----- */
- struct hci_conn {
- struct list_head list;
-+
-+ atomic_t refcnt;
-+ spinlock_t lock;
-+
- bdaddr_t dst;
- __u16 handle;
-+ __u16 state;
- __u8 type;
-- unsigned int sent;
-+ __u8 out;
-+ __u32 link_mode;
-+ unsigned long pend;
-+
-+ unsigned int sent;
-+
-+ struct sk_buff_head data_q;
-
-+ struct timer_list timer;
-+
- struct hci_dev *hdev;
- void *l2cap_data;
-+ void *sco_data;
- void *priv;
-
-- struct sk_buff_head data_q;
-+ struct hci_conn *link;
- };
-
--struct conn_hash {
-- struct list_head list;
-- spinlock_t lock;
-- unsigned int num;
--};
-+extern struct hci_proto *hci_proto[];
-+extern struct list_head hdev_list;
-+extern rwlock_t hdev_list_lock;
-+
-+/* ----- Inquiry cache ----- */
-+#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds
-+#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds
-+
-+#define inquiry_cache_lock(c) spin_lock(&c->lock)
-+#define inquiry_cache_unlock(c) spin_unlock(&c->lock)
-+#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
-+#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
-
--static inline void conn_hash_init(struct conn_hash *h)
-+static inline void inquiry_cache_init(struct hci_dev *hdev)
- {
-- INIT_LIST_HEAD(&h->list);
-- spin_lock_init(&h->lock);
-- h->num = 0;
-+ struct inquiry_cache *c = &hdev->inq_cache;
-+ spin_lock_init(&c->lock);
-+ c->list = NULL;
- }
-
--static inline void conn_hash_lock(struct conn_hash *h)
-+static inline long inquiry_cache_age(struct hci_dev *hdev)
- {
-- spin_lock(&h->lock);
-+ struct inquiry_cache *c = &hdev->inq_cache;
-+ return jiffies - c->timestamp;
- }
-
--static inline void conn_hash_unlock(struct conn_hash *h)
-+static inline long inquiry_entry_age(struct inquiry_entry *e)
- {
-- spin_unlock(&h->lock);
-+ return jiffies - e->timestamp;
- }
-
--static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
-+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
-+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info);
-+void inquiry_cache_flush(struct hci_dev *hdev);
-+int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
-+
-+/* ----- HCI Connections ----- */
-+enum {
-+ HCI_CONN_AUTH_PEND,
-+ HCI_CONN_ENCRYPT_PEND
-+};
-+
-+#define hci_conn_lock(c) spin_lock(&c->lock)
-+#define hci_conn_unlock(c) spin_unlock(&c->lock)
-+#define hci_conn_lock_bh(c) spin_lock_bh(&c->lock)
-+#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock)
-+
-+#define conn_hash_lock(d) spin_lock(&d->conn_hash->lock)
-+#define conn_hash_unlock(d) spin_unlock(&d->conn_hash->lock)
-+#define conn_hash_lock_bh(d) spin_lock_bh(&d->conn_hash->lock)
-+#define conn_hash_unlock_bh(d) spin_unlock_bh(&d->conn_hash->lock)
-+
-+static inline void conn_hash_init(struct hci_dev *hdev)
- {
-- list_add(&c->list, &h->list);
-- h->num++;
-+ struct conn_hash *h = &hdev->conn_hash;
-+ INIT_LIST_HEAD(&h->list);
-+ spin_lock_init(&h->lock);
-+ h->num = 0;
- }
-
--static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
-+static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
- {
-- conn_hash_lock(h);
-- __conn_hash_add(h, handle, c);
-- conn_hash_unlock(h);
-+ struct conn_hash *h = &hdev->conn_hash;
-+ list_add(&c->list, &h->list);
-+ h->num++;
- }
-
--static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c)
-+static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
- {
-+ struct conn_hash *h = &hdev->conn_hash;
- list_del(&c->list);
- h->num--;
- }
-
--static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c)
--{
-- conn_hash_lock(h);
-- __conn_hash_del(h, c);
-- conn_hash_unlock(h);
--}
--
--static inline struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
-+static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev,
-+ __u16 handle)
- {
-+ register struct conn_hash *h = &hdev->conn_hash;
- register struct list_head *p;
- register struct hci_conn *c;
-
-@@ -169,101 +238,95 @@
- return NULL;
- }
-
--static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle)
-+static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev,
-+ __u8 type, bdaddr_t *ba)
- {
-- struct hci_conn *conn;
-+ register struct conn_hash *h = &hdev->conn_hash;
-+ register struct list_head *p;
-+ register struct hci_conn *c;
-
-- conn_hash_lock(h);
-- conn = __conn_hash_lookup(h, handle);
-- conn_hash_unlock(h);
-- return conn;
-+ list_for_each(p, &h->list) {
-+ c = list_entry(p, struct hci_conn, list);
-+ if (c->type == type && !bacmp(&c->dst, ba))
-+ return c;
-+ }
-+ return NULL;
- }
-
--/* ----- HCI Devices ----- */
--struct hci_dev {
-- atomic_t refcnt;
--
-- char name[8];
-- __u32 flags;
-- __u16 id;
-- __u8 type;
-- bdaddr_t bdaddr;
-- __u8 features[8];
--
-- __u16 pkt_type;
--
-- atomic_t cmd_cnt;
-- unsigned int acl_cnt;
-- unsigned int sco_cnt;
--
-- unsigned int acl_mtu;
-- unsigned int sco_mtu;
-- unsigned int acl_max;
-- unsigned int sco_max;
--
-- void *driver_data;
-- void *l2cap_data;
-- void *priv;
--
-- struct tasklet_struct cmd_task;
-- struct tasklet_struct rx_task;
-- struct tasklet_struct tx_task;
--
-- struct sk_buff_head rx_q;
-- struct sk_buff_head raw_q;
-- struct sk_buff_head cmd_q;
--
-- struct sk_buff *sent_cmd;
--
-- struct semaphore req_lock;
-- wait_queue_head_t req_wait_q;
-- __u32 req_status;
-- __u32 req_result;
--
-- struct inquiry_cache inq_cache;
-+void hci_acl_connect(struct hci_conn *conn);
-+void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
-+void hci_add_sco(struct hci_conn *conn, __u16 handle);
-
-- struct conn_hash conn_hash;
-+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
-+int hci_conn_del(struct hci_conn *conn);
-+void hci_conn_hash_flush(struct hci_dev *hdev);
-
-- struct hci_dev_stats stat;
-+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
-+int hci_conn_auth(struct hci_conn *conn);
-+int hci_conn_encrypt(struct hci_conn *conn);
-
-- int (*open)(struct hci_dev *hdev);
-- int (*close)(struct hci_dev *hdev);
-- int (*flush)(struct hci_dev *hdev);
-- int (*send)(struct sk_buff *skb);
--};
-+static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout)
-+{
-+ mod_timer(&conn->timer, jiffies + timeout);
-+}
-
--static inline void hci_dev_hold(struct hci_dev *hdev)
-+static inline void hci_conn_del_timer(struct hci_conn *conn)
- {
-- atomic_inc(&hdev->refcnt);
-+ del_timer(&conn->timer);
- }
-
--static inline void hci_dev_put(struct hci_dev *hdev)
-+static inline void hci_conn_hold(struct hci_conn *conn)
- {
-- atomic_dec(&hdev->refcnt);
-+ atomic_inc(&conn->refcnt);
-+ hci_conn_del_timer(conn);
- }
-
--extern struct hci_dev *hci_dev_get(int index);
--extern int hci_register_dev(struct hci_dev *hdev);
--extern int hci_unregister_dev(struct hci_dev *hdev);
--extern int hci_dev_open(__u16 dev);
--extern int hci_dev_close(__u16 dev);
--extern int hci_dev_reset(__u16 dev);
--extern int hci_dev_reset_stat(__u16 dev);
--extern int hci_dev_info(unsigned long arg);
--extern int hci_dev_list(unsigned long arg);
--extern int hci_dev_setscan(unsigned long arg);
--extern int hci_dev_setauth(unsigned long arg);
--extern int hci_dev_setptype(unsigned long arg);
--extern int hci_conn_list(unsigned long arg);
--extern int hci_inquiry(unsigned long arg);
-+static inline void hci_conn_put(struct hci_conn *conn)
-+{
-+ if (atomic_dec_and_test(&conn->refcnt)) {
-+ if (conn->type == SCO_LINK)
-+ hci_conn_set_timer(conn, HZ / 100);
-+ else if (conn->out)
-+ hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT);
-+ }
-+}
-
--extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
--extern __u32 hci_dev_getmode(struct hci_dev *hdev);
-+/* ----- HCI Devices ----- */
-+static inline void hci_dev_put(struct hci_dev *d)
-+{
-+ if (atomic_dec_and_test(&d->refcnt))
-+ d->destruct(d);
-+}
-+#define hci_dev_hold(d) atomic_inc(&d->refcnt)
-+
-+#define hci_dev_lock(d) spin_lock(&d->lock)
-+#define hci_dev_unlock(d) spin_unlock(&d->lock)
-+#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock)
-+#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock)
-+
-+struct hci_dev *hci_dev_get(int index);
-+struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
-+int hci_register_dev(struct hci_dev *hdev);
-+int hci_unregister_dev(struct hci_dev *hdev);
-+int hci_suspend_dev(struct hci_dev *hdev);
-+int hci_resume_dev(struct hci_dev *hdev);
-+int hci_dev_open(__u16 dev);
-+int hci_dev_close(__u16 dev);
-+int hci_dev_reset(__u16 dev);
-+int hci_dev_reset_stat(__u16 dev);
-+int hci_dev_cmd(unsigned int cmd, unsigned long arg);
-+int hci_get_dev_list(unsigned long arg);
-+int hci_get_dev_info(unsigned long arg);
-+int hci_get_conn_list(unsigned long arg);
-+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg);
-+int hci_inquiry(unsigned long arg);
-
--extern int hci_recv_frame(struct sk_buff *skb);
-+int hci_recv_frame(struct sk_buff *skb);
-+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
-
- /* ----- LMP capabilities ----- */
- #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
-+#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
-
- /* ----- HCI tasks ----- */
- static inline void hci_sched_cmd(struct hci_dev *hdev)
-@@ -284,43 +347,130 @@
- /* ----- HCI protocols ----- */
- struct hci_proto {
- char *name;
-- __u32 id;
-- __u32 flags;
-+ unsigned int id;
-+ unsigned long flags;
-
- void *priv;
-
-- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr);
-- int (*connect_cfm) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
-+ int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
-+ int (*connect_cfm) (struct hci_conn *conn, __u8 status);
- int (*disconn_ind) (struct hci_conn *conn, __u8 reason);
-- int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
-+ int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
- int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
-+ int (*auth_cfm) (struct hci_conn *conn, __u8 status);
-+ int (*encrypt_cfm) (struct hci_conn *conn, __u8 status);
- };
-
--extern int hci_register_proto(struct hci_proto *hproto);
--extern int hci_unregister_proto(struct hci_proto *hproto);
--extern int hci_register_notifier(struct notifier_block *nb);
--extern int hci_unregister_notifier(struct notifier_block *nb);
--extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
--extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
--extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
--extern int hci_send_raw(struct sk_buff *skb);
--extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
--extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
-+static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+ register struct hci_proto *hp;
-+ int mask = 0;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->connect_ind)
-+ mask |= hp->connect_ind(hdev, bdaddr, type);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->connect_ind)
-+ mask |= hp->connect_ind(hdev, bdaddr, type);
-+
-+ return mask;
-+}
-+
-+static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->connect_cfm)
-+ hp->connect_cfm(conn, status);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->connect_cfm)
-+ hp->connect_cfm(conn, status);
-+}
-+
-+static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->disconn_ind)
-+ hp->disconn_ind(conn, reason);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->disconn_ind)
-+ hp->disconn_ind(conn, reason);
-+}
-+
-+static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->auth_cfm)
-+ hp->auth_cfm(conn, status);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->auth_cfm)
-+ hp->auth_cfm(conn, status);
-+}
-+
-+static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
-+{
-+ register struct hci_proto *hp;
-+
-+ hp = hci_proto[HCI_PROTO_L2CAP];
-+ if (hp && hp->encrypt_cfm)
-+ hp->encrypt_cfm(conn, status);
-+
-+ hp = hci_proto[HCI_PROTO_SCO];
-+ if (hp && hp->encrypt_cfm)
-+ hp->encrypt_cfm(conn, status);
-+}
-+
-+int hci_register_proto(struct hci_proto *hproto);
-+int hci_unregister_proto(struct hci_proto *hproto);
-+int hci_register_notifier(struct notifier_block *nb);
-+int hci_unregister_notifier(struct notifier_block *nb);
-+
-+int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
-+int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
-+int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
-+
-+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
-+
-+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
-
- /* ----- HCI Sockets ----- */
--extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
-+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
-
- /* HCI info for socket */
--#define hci_pi(sk) ((struct hci_pinfo *) &sk->protinfo)
-+#define hci_pi(sk) ((struct hci_pinfo *) &sk->tp_pinfo)
- struct hci_pinfo {
- struct hci_dev *hdev;
- struct hci_filter filter;
- __u32 cmsg_mask;
- };
-
-+/* HCI security filter */
-+#define HCI_SFLT_MAX_OGF 5
-+
-+struct hci_sec_filter {
-+ __u32 type_mask;
-+ __u32 event_mask[2];
-+ __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
-+};
-+
- /* ----- HCI requests ----- */
- #define HCI_REQ_DONE 0
- #define HCI_REQ_PEND 1
- #define HCI_REQ_CANCELED 2
-+
-+#define hci_req_lock(d) down(&d->req_lock)
-+#define hci_req_unlock(d) up(&d->req_lock)
-+
-+void hci_req_complete(struct hci_dev *hdev, int result);
-+void hci_req_cancel(struct hci_dev *hdev, int err);
-
- #endif /* __HCI_CORE_H */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_uart.h linux-2.4.18-mh9/include/net/bluetooth/hci_uart.h
---- linux-2.4.18/include/net/bluetooth/hci_uart.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/hci_uart.h Thu Jan 1 01:00:00 1970
-@@ -1,62 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef N_HCI
--#define N_HCI 15
--#endif
--
--#ifdef __KERNEL__
--
--#define tty2n_hci(tty) ((struct n_hci *)((tty)->disc_data))
--#define n_hci2tty(n_hci) ((n_hci)->tty)
--
--struct n_hci {
-- struct tty_struct *tty;
-- struct hci_dev hdev;
--
-- struct sk_buff_head txq;
-- unsigned long tx_state;
--
-- spinlock_t rx_lock;
-- unsigned long rx_state;
-- unsigned long rx_count;
-- struct sk_buff *rx_skb;
--};
--
--/* Transmit states */
--#define TRANS_SENDING 1
--#define TRANS_WAKEUP 2
--
--/* Receiver States */
--#define WAIT_PACKET_TYPE 0
--#define WAIT_EVENT_HDR 1
--#define WAIT_ACL_HDR 2
--#define WAIT_SCO_HDR 3
--#define WAIT_DATA 4
--
--#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_usb.h linux-2.4.18-mh9/include/net/bluetooth/hci_usb.h
---- linux-2.4.18/include/net/bluetooth/hci_usb.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/hci_usb.h Thu Jan 1 01:00:00 1970
-@@ -1,68 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifdef __KERNEL__
--
--/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
--#define HCI_DEV_CLASS 0xe0 /* Wireless class */
--#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */
--#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */
--
--#define HCI_CTRL_REQ 0x20
--
--struct hci_usb {
-- struct usb_device *udev;
--
-- devrequest dev_req;
-- struct urb *ctrl_urb;
-- struct urb *intr_urb;
-- struct urb *read_urb;
-- struct urb *write_urb;
--
-- __u8 *read_buf;
-- __u8 *intr_buf;
-- struct sk_buff *intr_skb;
-- int intr_count;
--
-- __u8 bulk_out_ep_addr;
-- __u8 bulk_in_ep_addr;
-- __u8 intr_in_ep_addr;
-- __u8 intr_in_interval;
--
-- struct hci_dev hdev;
--
-- unsigned long tx_state;
-- struct sk_buff_head tx_ctrl_q;
-- struct sk_buff_head tx_write_q;
--};
--
--/* Transmit states */
--#define HCI_TX_CTRL 1
--#define HCI_TX_WRITE 2
--
--#endif /* __KERNEL__ */
-diff -urN linux-2.4.18/include/net/bluetooth/hci_vhci.h linux-2.4.18-mh9/include/net/bluetooth/hci_vhci.h
---- linux-2.4.18/include/net/bluetooth/hci_vhci.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/hci_vhci.h Thu Jan 1 01:00:00 1970
-@@ -1,50 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef __HCI_VHCI_H
--#define __HCI_VHCI_H
--
--#ifdef __KERNEL__
--
--struct hci_vhci_struct {
-- struct hci_dev hdev;
-- __u32 flags;
-- wait_queue_head_t read_wait;
-- struct sk_buff_head readq;
-- struct fasync_struct *fasync;
--};
--
--/* VHCI device flags */
--#define VHCI_FASYNC 0x0010
--
--#endif /* __KERNEL__ */
--
--#define VHCI_DEV "/dev/vhci"
--#define VHCI_MINOR 250
--
--#endif /* __HCI_VHCI_H */
-diff -urN linux-2.4.18/include/net/bluetooth/l2cap.h linux-2.4.18-mh9/include/net/bluetooth/l2cap.h
---- linux-2.4.18/include/net/bluetooth/l2cap.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/l2cap.h Mon Aug 25 18:38:12 2003
-@@ -23,22 +23,17 @@
- */
-
- /*
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __L2CAP_H
- #define __L2CAP_H
-
--#include <asm/types.h>
--#include <asm/byteorder.h>
--
- /* L2CAP defaults */
- #define L2CAP_DEFAULT_MTU 672
- #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
-
- #define L2CAP_CONN_TIMEOUT (HZ * 40)
--#define L2CAP_DISCONN_TIMEOUT (HZ * 2)
--#define L2CAP_CONN_IDLE_TIMEOUT (HZ * 60)
-
- /* L2CAP socket address */
- struct sockaddr_l2 {
-@@ -47,17 +42,12 @@
- bdaddr_t l2_bdaddr;
- };
-
--/* set/get sockopt defines */
--#define L2CAP_OPTIONS 0x01
-+/* Socket options */
-+#define L2CAP_OPTIONS 0x01
- struct l2cap_options {
- __u16 omtu;
- __u16 imtu;
- __u16 flush_to;
-- __u32 token_rate;
-- __u32 bucket_size;
-- __u32 pick_band;
-- __u32 latency;
-- __u32 delay_var;
- };
-
- #define L2CAP_CONNINFO 0x02
-@@ -65,6 +55,27 @@
- __u16 hci_handle;
- };
-
-+#define L2CAP_LM 0x03
-+#define L2CAP_LM_MASTER 0x0001
-+#define L2CAP_LM_AUTH 0x0002
-+#define L2CAP_LM_ENCRYPT 0x0004
-+#define L2CAP_LM_TRUSTED 0x0008
-+#define L2CAP_LM_RELIABLE 0x0010
-+
-+#define L2CAP_QOS 0x04
-+struct l2cap_qos {
-+ __u16 service_type;
-+ __u32 token_rate;
-+ __u32 token_bucket_size;
-+ __u32 peak_bandwidth;
-+ __u32 latency;
-+ __u32 delay_variation;
-+};
-+
-+#define L2CAP_SERV_NO_TRAFFIC 0x00
-+#define L2CAP_SERV_BEST_EFFORT 0x01
-+#define L2CAP_SERV_GUARANTEED 0x02
-+
- /* L2CAP command codes */
- #define L2CAP_COMMAND_REJ 0x01
- #define L2CAP_CONN_REQ 0x02
-@@ -79,7 +90,6 @@
- #define L2CAP_INFO_RSP 0x0b
-
- /* L2CAP structures */
--
- typedef struct {
- __u16 len;
- __u16 cid;
-@@ -112,11 +122,17 @@
- } __attribute__ ((packed)) l2cap_conn_rsp;
- #define L2CAP_CONN_RSP_SIZE 8
-
--#define L2CAP_CONN_SUCCESS 0x0000
--#define L2CAP_CONN_PEND 0x0001
--#define L2CAP_CONN_BAD_PSM 0x0002
--#define L2CAP_CONN_SEC_BLOCK 0x0003
--#define L2CAP_CONN_NO_MEM 0x0004
-+/* connect result */
-+#define L2CAP_CR_SUCCESS 0x0000
-+#define L2CAP_CR_PEND 0x0001
-+#define L2CAP_CR_BAD_PSM 0x0002
-+#define L2CAP_CR_SEC_BLOCK 0x0003
-+#define L2CAP_CR_NO_MEM 0x0004
-+
-+/* connect status */
-+#define L2CAP_CS_NO_INFO 0x0000
-+#define L2CAP_CS_AUTHEN_PEND 0x0001
-+#define L2CAP_CS_AUTHOR_PEND 0x0002
-
- typedef struct {
- __u16 dcid;
-@@ -147,6 +163,8 @@
- #define L2CAP_CONF_FLUSH_TO 0x02
- #define L2CAP_CONF_QOS 0x03
-
-+#define L2CAP_CONF_MAX_SIZE 22
-+
- typedef struct {
- __u16 dcid;
- __u16 scid;
-@@ -158,5 +176,75 @@
- __u16 scid;
- } __attribute__ ((packed)) l2cap_disconn_rsp;
- #define L2CAP_DISCONN_RSP_SIZE 4
-+
-+typedef struct {
-+ __u16 type;
-+ __u8 data[0];
-+} __attribute__ ((packed)) l2cap_info_req;
-+#define L2CAP_INFO_REQ_SIZE 2
-+
-+typedef struct {
-+ __u16 type;
-+ __u16 result;
-+ __u8 data[0];
-+} __attribute__ ((packed)) l2cap_info_rsp;
-+#define L2CAP_INFO_RSP_SIZE 4
-+
-+/* ----- L2CAP connections ----- */
-+struct l2cap_chan_list {
-+ struct sock *head;
-+ rwlock_t lock;
-+ long num;
-+};
-+
-+struct l2cap_conn {
-+ struct hci_conn *hcon;
-+
-+ bdaddr_t *dst;
-+ bdaddr_t *src;
-+
-+ unsigned int mtu;
-+
-+ spinlock_t lock;
-+
-+ struct sk_buff *rx_skb;
-+ __u32 rx_len;
-+ __u8 rx_ident;
-+ __u8 tx_ident;
-+
-+ struct l2cap_chan_list chan_list;
-+};
-+
-+/* ----- L2CAP channel and socket info ----- */
-+#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->tp_pinfo)
-+
-+struct l2cap_pinfo {
-+ __u16 psm;
-+ __u16 dcid;
-+ __u16 scid;
-+
-+ __u16 imtu;
-+ __u16 omtu;
-+ __u16 flush_to;
-+
-+ __u32 link_mode;
-+
-+ __u8 conf_state;
-+ __u8 conf_retry;
-+ __u16 conf_mtu;
-+
-+ __u8 ident;
-+
-+ struct l2cap_conn *conn;
-+ struct sock *next_c;
-+ struct sock *prev_c;
-+};
-+
-+#define L2CAP_CONF_REQ_SENT 0x01
-+#define L2CAP_CONF_INPUT_DONE 0x02
-+#define L2CAP_CONF_OUTPUT_DONE 0x04
-+#define L2CAP_CONF_MAX_RETRIES 2
-+
-+void l2cap_load(void);
-
- #endif /* __L2CAP_H */
-diff -urN linux-2.4.18/include/net/bluetooth/l2cap_core.h linux-2.4.18-mh9/include/net/bluetooth/l2cap_core.h
---- linux-2.4.18/include/net/bluetooth/l2cap_core.h Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/include/net/bluetooth/l2cap_core.h Thu Jan 1 01:00:00 1970
-@@ -1,144 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * $Id$
-- */
--
--#ifndef __L2CAP_CORE_H
--#define __L2CAP_CORE_H
--
--#ifdef __KERNEL__
--
--/* ----- L2CAP interface ----- */
--struct l2cap_iff {
-- struct list_head list;
-- struct hci_dev *hdev;
-- bdaddr_t *bdaddr;
-- __u16 mtu;
-- spinlock_t lock;
-- struct list_head conn_list;
--};
--
--static inline void l2cap_iff_lock(struct l2cap_iff *iff)
--{
-- spin_lock(&iff->lock);
--}
--
--static inline void l2cap_iff_unlock(struct l2cap_iff *iff)
--{
-- spin_unlock(&iff->lock);
--}
--
--/* ----- L2CAP connections ----- */
--struct l2cap_chan_list {
-- struct sock *head;
-- rwlock_t lock;
-- long num;
--};
--
--struct l2cap_conn {
-- struct l2cap_iff *iff;
-- struct list_head list;
--
-- struct hci_conn *hconn;
--
-- __u16 state;
-- __u8 out;
-- bdaddr_t src;
-- bdaddr_t dst;
--
-- spinlock_t lock;
-- atomic_t refcnt;
--
-- struct sk_buff *rx_skb;
-- __u32 rx_len;
-- __u8 rx_ident;
-- __u8 tx_ident;
--
-- struct l2cap_chan_list chan_list;
--
-- struct timer_list timer;
--};
--
--static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
--{
-- list_add(&c->list, &iff->conn_list);
--}
--
--static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
--{
-- list_del(&c->list);
--}
--
--/* ----- L2CAP channel and socket info ----- */
--#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->protinfo)
--
--struct l2cap_accept_q {
-- struct sock *head;
-- struct sock *tail;
--};
--
--struct l2cap_pinfo {
-- bdaddr_t src;
-- bdaddr_t dst;
-- __u16 psm;
-- __u16 dcid;
-- __u16 scid;
-- __u32 flags;
--
-- __u16 imtu;
-- __u16 omtu;
-- __u16 flush_to;
--
-- __u8 conf_state;
-- __u16 conf_mtu;
--
-- __u8 ident;
--
-- struct l2cap_conn *conn;
-- struct sock *next_c;
-- struct sock *prev_c;
--
-- struct sock *parent;
-- struct sock *next_q;
-- struct sock *prev_q;
--
-- struct l2cap_accept_q accept_q;
--};
--
--#define CONF_REQ_SENT 0x01
--#define CONF_INPUT_DONE 0x02
--#define CONF_OUTPUT_DONE 0x04
--
--extern struct bluez_sock_list l2cap_sk_list;
--extern struct list_head l2cap_iff_list;
--extern rwlock_t l2cap_rt_lock;
--
--extern void l2cap_register_proc(void);
--extern void l2cap_unregister_proc(void);
--
--#endif /* __KERNEL__ */
--
--#endif /* __L2CAP_CORE_H */
-diff -urN linux-2.4.18/include/net/bluetooth/rfcomm.h linux-2.4.18-mh9/include/net/bluetooth/rfcomm.h
---- linux-2.4.18/include/net/bluetooth/rfcomm.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/include/net/bluetooth/rfcomm.h Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,356 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ RPN support - Dirk Husemann <hud@zurich.ibm.com>
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __RFCOMM_H
-+#define __RFCOMM_H
-+
-+#define RFCOMM_PSM 3
-+
-+#define RFCOMM_CONN_TIMEOUT (HZ * 30)
-+#define RFCOMM_DISC_TIMEOUT (HZ * 20)
-+
-+#define RFCOMM_DEFAULT_MTU 127
-+#define RFCOMM_DEFAULT_CREDITS 7
-+
-+#define RFCOMM_MAX_L2CAP_MTU 1024
-+#define RFCOMM_MAX_CREDITS 40
-+
-+#define RFCOMM_SKB_HEAD_RESERVE 8
-+#define RFCOMM_SKB_TAIL_RESERVE 2
-+#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
-+
-+#define RFCOMM_SABM 0x2f
-+#define RFCOMM_DISC 0x43
-+#define RFCOMM_UA 0x63
-+#define RFCOMM_DM 0x0f
-+#define RFCOMM_UIH 0xef
-+
-+#define RFCOMM_TEST 0x08
-+#define RFCOMM_FCON 0x28
-+#define RFCOMM_FCOFF 0x18
-+#define RFCOMM_MSC 0x38
-+#define RFCOMM_RPN 0x24
-+#define RFCOMM_RLS 0x14
-+#define RFCOMM_PN 0x20
-+#define RFCOMM_NSC 0x04
-+
-+#define RFCOMM_V24_FC 0x02
-+#define RFCOMM_V24_RTC 0x04
-+#define RFCOMM_V24_RTR 0x08
-+#define RFCOMM_V24_IC 0x40
-+#define RFCOMM_V24_DV 0x80
-+
-+#define RFCOMM_RPN_BR_2400 0x0
-+#define RFCOMM_RPN_BR_4800 0x1
-+#define RFCOMM_RPN_BR_7200 0x2
-+#define RFCOMM_RPN_BR_9600 0x3
-+#define RFCOMM_RPN_BR_19200 0x4
-+#define RFCOMM_RPN_BR_38400 0x5
-+#define RFCOMM_RPN_BR_57600 0x6
-+#define RFCOMM_RPN_BR_115200 0x7
-+#define RFCOMM_RPN_BR_230400 0x8
-+
-+#define RFCOMM_RPN_DATA_5 0x0
-+#define RFCOMM_RPN_DATA_6 0x1
-+#define RFCOMM_RPN_DATA_7 0x2
-+#define RFCOMM_RPN_DATA_8 0x3
-+
-+#define RFCOMM_RPN_STOP_1 0
-+#define RFCOMM_RPN_STOP_15 1
-+
-+#define RFCOMM_RPN_PARITY_NONE 0x0
-+#define RFCOMM_RPN_PARITY_ODD 0x4
-+#define RFCOMM_RPN_PARITY_EVEN 0x5
-+#define RFCOMM_RPN_PARITY_MARK 0x6
-+#define RFCOMM_RPN_PARITY_SPACE 0x7
-+
-+#define RFCOMM_RPN_FLOW_NONE 0x00
-+
-+#define RFCOMM_RPN_XON_CHAR 0x11
-+#define RFCOMM_RPN_XOFF_CHAR 0x13
-+
-+#define RFCOMM_RPN_PM_BITRATE 0x0001
-+#define RFCOMM_RPN_PM_DATA 0x0002
-+#define RFCOMM_RPN_PM_STOP 0x0004
-+#define RFCOMM_RPN_PM_PARITY 0x0008
-+#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010
-+#define RFCOMM_RPN_PM_XON 0x0020
-+#define RFCOMM_RPN_PM_XOFF 0x0040
-+#define RFCOMM_RPN_PM_FLOW 0x3F00
-+
-+#define RFCOMM_RPN_PM_ALL 0x3F7F
-+
-+struct rfcomm_hdr {
-+ u8 addr;
-+ u8 ctrl;
-+ u8 len; // Actual size can be 2 bytes
-+} __attribute__ ((packed));
-+
-+struct rfcomm_cmd {
-+ u8 addr;
-+ u8 ctrl;
-+ u8 len;
-+ u8 fcs;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_mcc {
-+ u8 type;
-+ u8 len;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_pn {
-+ u8 dlci;
-+ u8 flow_ctrl;
-+ u8 priority;
-+ u8 ack_timer;
-+ u16 mtu;
-+ u8 max_retrans;
-+ u8 credits;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_rpn {
-+ u8 dlci;
-+ u8 bit_rate;
-+ u8 line_settings;
-+ u8 flow_ctrl;
-+ u8 xon_char;
-+ u8 xoff_char;
-+ u16 param_mask;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_rls {
-+ u8 dlci;
-+ u8 status;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_msc {
-+ u8 dlci;
-+ u8 v24_sig;
-+} __attribute__ ((packed));
-+
-+/* ---- Core structures, flags etc ---- */
-+
-+struct rfcomm_session {
-+ struct list_head list;
-+ struct socket *sock;
-+ unsigned long state;
-+ unsigned long flags;
-+ atomic_t refcnt;
-+ int initiator;
-+
-+ /* Default DLC parameters */
-+ uint mtu;
-+ uint credits;
-+
-+ struct list_head dlcs;
-+};
-+
-+struct rfcomm_dlc {
-+ struct list_head list;
-+ struct rfcomm_session *session;
-+ struct sk_buff_head tx_queue;
-+ struct timer_list timer;
-+
-+ spinlock_t lock;
-+ unsigned long state;
-+ unsigned long flags;
-+ atomic_t refcnt;
-+ u8 dlci;
-+ u8 addr;
-+ u8 priority;
-+ u8 v24_sig;
-+ u8 mscex;
-+
-+ uint mtu;
-+ uint credits;
-+ uint rx_credits;
-+ uint tx_credits;
-+
-+ void *owner;
-+
-+ void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
-+ void (*state_change)(struct rfcomm_dlc *d, int err);
-+ void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
-+};
-+
-+/* DLC and session flags */
-+#define RFCOMM_RX_THROTTLED 0
-+#define RFCOMM_TX_THROTTLED 1
-+#define RFCOMM_MSC_PENDING 2
-+#define RFCOMM_TIMED_OUT 3
-+
-+/* Scheduling flags and events */
-+#define RFCOMM_SCHED_STATE 0
-+#define RFCOMM_SCHED_RX 1
-+#define RFCOMM_SCHED_TX 2
-+#define RFCOMM_SCHED_TIMEO 3
-+#define RFCOMM_SCHED_WAKEUP 31
-+
-+/* MSC exchange flags */
-+#define RFCOMM_MSCEX_TX 1
-+#define RFCOMM_MSCEX_RX 2
-+#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
-+
-+extern struct task_struct *rfcomm_thread;
-+extern unsigned long rfcomm_event;
-+
-+static inline void rfcomm_schedule(uint event)
-+{
-+ if (!rfcomm_thread)
-+ return;
-+ set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-+ wake_up_process(rfcomm_thread);
-+}
-+
-+extern struct semaphore rfcomm_sem;
-+#define rfcomm_lock() down(&rfcomm_sem);
-+#define rfcomm_unlock() up(&rfcomm_sem);
-+
-+/* ---- RFCOMM DLCs (channels) ---- */
-+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
-+void rfcomm_dlc_free(struct rfcomm_dlc *d);
-+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
-+int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
-+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
-+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
-+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
-+
-+#define rfcomm_dlc_lock(d) spin_lock(&d->lock)
-+#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock)
-+
-+static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
-+{
-+ atomic_inc(&d->refcnt);
-+}
-+
-+static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
-+{
-+ if (atomic_dec_and_test(&d->refcnt))
-+ rfcomm_dlc_free(d);
-+}
-+
-+extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
-+extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
-+
-+static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-+{
-+ if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+ __rfcomm_dlc_throttle(d);
-+}
-+
-+static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-+{
-+ if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+ __rfcomm_dlc_unthrottle(d);
-+}
-+
-+/* ---- RFCOMM sessions ---- */
-+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
-+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
-+void rfcomm_session_del(struct rfcomm_session *s);
-+void rfcomm_session_close(struct rfcomm_session *s, int err);
-+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
-+
-+static inline void rfcomm_session_hold(struct rfcomm_session *s)
-+{
-+ atomic_inc(&s->refcnt);
-+}
-+
-+static inline void rfcomm_session_put(struct rfcomm_session *s)
-+{
-+ if (atomic_dec_and_test(&s->refcnt))
-+ rfcomm_session_del(s);
-+}
-+
-+/* ---- RFCOMM chechsum ---- */
-+extern u8 rfcomm_crc_table[];
-+
-+/* ---- RFCOMM sockets ---- */
-+struct sockaddr_rc {
-+ sa_family_t rc_family;
-+ bdaddr_t rc_bdaddr;
-+ u8 rc_channel;
-+};
-+
-+#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->tp_pinfo)
-+
-+struct rfcomm_pinfo {
-+ struct rfcomm_dlc *dlc;
-+ u8 channel;
-+};
-+
-+int rfcomm_init_sockets(void);
-+void rfcomm_cleanup_sockets(void);
-+
-+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
-+
-+/* ---- RFCOMM TTY ---- */
-+#define RFCOMM_MAX_DEV 256
-+
-+#define RFCOMMCREATEDEV _IOW('R', 200, int)
-+#define RFCOMMRELEASEDEV _IOW('R', 201, int)
-+#define RFCOMMGETDEVLIST _IOR('R', 210, int)
-+#define RFCOMMGETDEVINFO _IOR('R', 211, int)
-+#define RFCOMMSTEALDLC _IOW('R', 220, int)
-+
-+#define RFCOMM_REUSE_DLC 0
-+#define RFCOMM_RELEASE_ONHUP 1
-+#define RFCOMM_HANGUP_NOW 2
-+#define RFCOMM_TTY_ATTACHED 3
-+
-+struct rfcomm_dev_req {
-+ s16 dev_id;
-+ u32 flags;
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+ u8 channel;
-+};
-+
-+struct rfcomm_dev_info {
-+ s16 id;
-+ u32 flags;
-+ u16 state;
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+ u8 channel;
-+};
-+
-+struct rfcomm_dev_list_req {
-+ u16 dev_num;
-+ struct rfcomm_dev_info dev_info[0];
-+};
-+
-+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
-+int rfcomm_init_ttys(void);
-+void rfcomm_cleanup_ttys(void);
-+
-+#endif /* __RFCOMM_H */
-diff -urN linux-2.4.18/include/net/bluetooth/sco.h linux-2.4.18-mh9/include/net/bluetooth/sco.h
---- linux-2.4.18/include/net/bluetooth/sco.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/include/net/bluetooth/sco.h Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,81 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef __SCO_H
-+#define __SCO_H
-+
-+/* SCO defaults */
-+#define SCO_DEFAULT_MTU 500
-+#define SCO_DEFAULT_FLUSH_TO 0xFFFF
-+
-+#define SCO_CONN_TIMEOUT (HZ * 40)
-+#define SCO_DISCONN_TIMEOUT (HZ * 2)
-+#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
-+
-+/* SCO socket address */
-+struct sockaddr_sco {
-+ sa_family_t sco_family;
-+ bdaddr_t sco_bdaddr;
-+};
-+
-+/* set/get sockopt defines */
-+#define SCO_OPTIONS 0x01
-+struct sco_options {
-+ __u16 mtu;
-+};
-+
-+#define SCO_CONNINFO 0x02
-+struct sco_conninfo {
-+ __u16 hci_handle;
-+};
-+
-+/* ---- SCO connections ---- */
-+struct sco_conn {
-+ struct hci_conn *hcon;
-+
-+ bdaddr_t *dst;
-+ bdaddr_t *src;
-+
-+ spinlock_t lock;
-+ struct sock *sk;
-+
-+ unsigned int mtu;
-+};
-+
-+#define sco_conn_lock(c) spin_lock(&c->lock);
-+#define sco_conn_unlock(c) spin_unlock(&c->lock);
-+
-+/* ----- SCO socket info ----- */
-+#define sco_pi(sk) ((struct sco_pinfo *) &sk->tp_pinfo)
-+
-+struct sco_pinfo {
-+ __u32 flags;
-+ struct sco_conn *conn;
-+};
-+
-+#endif /* __SCO_H */
-diff -urN linux-2.4.18/include/pcmcia/ciscode.h linux-2.4.18-mh9/include/pcmcia/ciscode.h
---- linux-2.4.18/include/pcmcia/ciscode.h Fri Dec 21 18:42:04 2001
-+++ linux-2.4.18-mh9/include/pcmcia/ciscode.h Mon Aug 25 18:38:12 2003
-@@ -1,5 +1,5 @@
- /*
-- * ciscode.h 1.48 2001/08/24 12:16:12
-+ * ciscode.h 1.57 2002/11/03 20:38:14
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
-@@ -60,6 +60,10 @@
- #define PRODID_INTEL_DUAL_RS232 0x0301
- #define PRODID_INTEL_2PLUS 0x8422
-
-+#define MANFID_KME 0x0032
-+#define PRODID_KME_KXLC005_A 0x0704
-+#define PRODID_KME_KXLC005_B 0x2904
-+
- #define MANFID_LINKSYS 0x0143
- #define PRODID_LINKSYS_PCMLM28 0xc0ab
- #define PRODID_LINKSYS_3400 0x3341
-@@ -94,6 +98,8 @@
- #define PRODID_OSITECH_JACK_336 0x0007
- #define PRODID_OSITECH_SEVEN 0x0008
-
-+#define MANFID_OXSEMI 0x0279
-+
- #define MANFID_PIONEER 0x000b
-
- #define MANFID_PSION 0x016c
-@@ -103,6 +109,7 @@
- #define PRODID_QUATECH_SPP100 0x0003
- #define PRODID_QUATECH_DUAL_RS232 0x0012
- #define PRODID_QUATECH_DUAL_RS232_D1 0x0007
-+#define PRODID_QUATECH_DUAL_RS232_D2 0x0052
- #define PRODID_QUATECH_QUAD_RS232 0x001b
- #define PRODID_QUATECH_DUAL_RS422 0x000e
- #define PRODID_QUATECH_QUAD_RS422 0x0045
-@@ -120,8 +127,11 @@
-
- #define MANFID_TDK 0x0105
- #define PRODID_TDK_CF010 0x0900
-+#define PRODID_TDK_GN3410 0x4815
-
- #define MANFID_TOSHIBA 0x0098
-+
-+#define MANFID_UNGERMANN 0x02c0
-
- #define MANFID_XIRCOM 0x0105
-
-diff -urN linux-2.4.18/lib/Config.in linux-2.4.18-mh9/lib/Config.in
---- linux-2.4.18/lib/Config.in Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/lib/Config.in Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,12 @@
-+#
-+# Library configuration
-+#
-+mainmenu_option next_comment
-+comment 'Library routines'
-+
-+if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
-+ "$CONFIG_HOTPLUG" = "y" ]; then
-+ tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER
-+fi
-+
-+endmenu
-diff -urN linux-2.4.18/lib/Makefile linux-2.4.18-mh9/lib/Makefile
---- linux-2.4.18/lib/Makefile Tue Sep 18 00:31:15 2001
-+++ linux-2.4.18-mh9/lib/Makefile Mon Aug 25 18:38:12 2003
-@@ -8,12 +8,16 @@
-
- L_TARGET := lib.a
-
--export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
-+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
-+ firmware_class.o
-
- obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
-
-+obj-$(CONFIG_FW_LOADER) += firmware_class.o
- obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
- obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
-+
-+include $(TOPDIR)/drivers/bluetooth/Makefile.lib
-
- ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
- obj-y += dec_and_lock.o
-diff -urN linux-2.4.18/lib/firmware_class.c linux-2.4.18-mh9/lib/firmware_class.c
---- linux-2.4.18/lib/firmware_class.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/lib/firmware_class.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,571 @@
-+/*
-+ * firmware_class.c - Multi purpose firmware loading support
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Please see Documentation/firmware_class/ for more information.
-+ *
-+ */
-+/*
-+ * Based on kernel/kmod.c and drivers/usb/usb.c
-+ */
-+/*
-+ kernel/kmod.c
-+ Kirk Petersen
-+
-+ Reorganized not to be a daemon by Adam Richter, with guidance
-+ from Greg Zornetzer.
-+
-+ Modified to avoid chroot and file sharing problems.
-+ Mikael Pettersson
-+
-+ Limit the concurrent number of kmod modprobes to catch loops from
-+ "modprobe needs a service that is in a module".
-+ Keith Owens <kaos@ocs.com.au> December 1999
-+
-+ Unblock all signals when we exec a usermode process.
-+ Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
-+*/
-+/*
-+ * drivers/usb/usb.c
-+ *
-+ * (C) Copyright Linus Torvalds 1999
-+ * (C) Copyright Johannes Erdfelt 1999-2001
-+ * (C) Copyright Andreas Gal 1999
-+ * (C) Copyright Gregory P. Smith 1999
-+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
-+ * (C) Copyright Randy Dunlap 2000
-+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
-+ * (C) Copyright Yggdrasil Computing, Inc. 2000
-+ * (usb_device_id matching changes by Adam J. Richter)
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/kmod.h>
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+#include <asm/hardirq.h>
-+
-+#include "linux/firmware.h"
-+
-+MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
-+MODULE_DESCRIPTION("Multi purpose firmware loading support");
-+MODULE_LICENSE("GPL");
-+
-+#define err(format, arg...) \
-+ printk(KERN_ERR "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define warn(format, arg...) \
-+ printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define dbg(format, arg...) \
-+ printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+
-+static int loading_timeout = 10; /* In seconds */
-+static struct proc_dir_entry *proc_dir_timeout;
-+static struct proc_dir_entry *proc_dir;
-+
-+#ifdef CONFIG_HOTPLUG
-+
-+static int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+ char *argv[3], **envp, *buf, *scratch;
-+ int i = 0;
-+
-+ int retval = 0;
-+
-+ if (!hotplug_path[0])
-+ return -ENOENT;
-+ if (in_interrupt()) {
-+ err("in_interrupt");
-+ return -EFAULT;
-+ }
-+ if (!current->fs->root) {
-+ warn("call_policy %s -- no FS yet", verb);
-+ return -EPERM;
-+ }
-+
-+ if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
-+ err("unable to allocate envp");
-+ return -ENOMEM;
-+ }
-+ if (!(buf = kmalloc(256, GFP_KERNEL))) {
-+ kfree(envp);
-+ err("unable to allocate buf");
-+ return -ENOMEM;
-+ }
-+
-+ /* only one standardized param to hotplug command: type */
-+ argv[0] = hotplug_path;
-+ argv[1] = "firmware";
-+ argv[2] = 0;
-+
-+ /* minimal command environment */
-+ envp[i++] = "HOME=/";
-+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+
-+#ifdef DEBUG
-+ /* hint that policy agent should enter no-stdout debug mode */
-+ envp[i++] = "DEBUG=kernel";
-+#endif
-+ scratch = buf;
-+
-+ if (device) {
-+ envp[i++] = scratch;
-+ scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
-+ "DEVPATH=/driver/firmware/%s", device) + 1;
-+ }
-+
-+ envp[i++] = scratch;
-+ scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
-+
-+ envp[i++] = scratch;
-+ scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
-+ "FIRMWARE=%s", name) + 1;
-+
-+ envp[i++] = 0;
-+
-+#ifdef DEBUG
-+ dbg("firmware: %s %s %s", argv[0], argv[1], verb);
-+#endif
-+
-+ retval = call_usermodehelper(argv[0], argv, envp);
-+ if (retval) {
-+ printk("call_usermodehelper return %d\n", retval);
-+ }
-+
-+ kfree(buf);
-+ kfree(envp);
-+ return retval;
-+}
-+#else
-+
-+static inline int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+ return -ENOENT;
-+}
-+
-+#endif /* CONFIG_HOTPLUG */
-+
-+struct firmware_priv {
-+ struct completion completion;
-+ struct proc_dir_entry *proc_dir;
-+ struct proc_dir_entry *attr_data;
-+ struct proc_dir_entry *attr_loading;
-+ struct firmware *fw;
-+ int loading;
-+ int abort;
-+ int alloc_size;
-+ struct timer_list timeout;
-+};
-+
-+static int
-+firmware_timeout_show(char *buf, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ return sprintf(buf, "%d\n", loading_timeout);
-+}
-+
-+/**
-+ * firmware_timeout_store:
-+ * Description:
-+ * Sets the number of seconds to wait for the firmware. Once
-+ * this expires an error will be return to the driver and no
-+ * firmware will be provided.
-+ *
-+ * Note: zero means 'wait for ever'
-+ *
-+ **/
-+static int
-+firmware_timeout_store(struct file *file, const char *buf,
-+ unsigned long count, void *data)
-+{
-+ loading_timeout = simple_strtol(buf, NULL, 10);
-+ return count;
-+}
-+
-+static int
-+firmware_loading_show(char *buf, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ return sprintf(buf, "%d\n", fw_priv->loading);
-+}
-+
-+/**
-+ * firmware_loading_store: - loading control file
-+ * Description:
-+ * The relevant values are:
-+ *
-+ * 1: Start a load, discarding any previous partial load.
-+ * 0: Conclude the load and handle the data to the driver code.
-+ * -1: Conclude the load with an error and discard any written data.
-+ **/
-+static int
-+firmware_loading_store(struct file *file, const char *buf,
-+ unsigned long count, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ int prev_loading = fw_priv->loading;
-+
-+ fw_priv->loading = simple_strtol(buf, NULL, 10);
-+
-+ switch (fw_priv->loading) {
-+ case -1:
-+ fw_priv->abort = 1;
-+ wmb();
-+ complete(&fw_priv->completion);
-+ break;
-+ case 1:
-+ kfree(fw_priv->fw->data);
-+ fw_priv->fw->data = NULL;
-+ fw_priv->fw->size = 0;
-+ fw_priv->alloc_size = 0;
-+ break;
-+ case 0:
-+ if (prev_loading == 1)
-+ complete(&fw_priv->completion);
-+ break;
-+ }
-+
-+ return count;
-+}
-+
-+static int
-+firmware_data_read(char *buffer, char **start, off_t offset,
-+ int count, int *eof, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ struct firmware *fw = fw_priv->fw;
-+
-+ if (offset > fw->size)
-+ return 0;
-+ if (offset + count > fw->size)
-+ count = fw->size - offset;
-+
-+ memcpy(buffer, fw->data + offset, count);
-+ *start = (void *) ((long) count);
-+ return count;
-+}
-+static int
-+fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
-+{
-+ u8 *new_data;
-+ int new_size;
-+
-+ if (min_size <= fw_priv->alloc_size)
-+ return 0;
-+ if((min_size % PAGE_SIZE) == 0)
-+ new_size = min_size;
-+ else
-+ new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
-+ new_data = vmalloc(new_size);
-+ if (!new_data) {
-+ printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
-+ /* Make sure that we don't keep incomplete data */
-+ fw_priv->abort = 1;
-+ return -ENOMEM;
-+ }
-+ fw_priv->alloc_size = new_size;
-+ if (fw_priv->fw->data) {
-+ memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
-+ vfree(fw_priv->fw->data);
-+ }
-+ fw_priv->fw->data = new_data;
-+ BUG_ON(min_size > fw_priv->alloc_size);
-+ return 0;
-+}
-+
-+/**
-+ * firmware_data_write:
-+ *
-+ * Description:
-+ *
-+ * Data written to the 'data' attribute will be later handled to
-+ * the driver as a firmware image.
-+ **/
-+static int
-+firmware_data_write(struct file *file, const char *buffer,
-+ unsigned long count, void *data)
-+{
-+ struct firmware_priv *fw_priv = data;
-+ struct firmware *fw = fw_priv->fw;
-+ int offset = file->f_pos;
-+ int retval;
-+
-+ retval = fw_realloc_buffer(fw_priv, offset + count);
-+ if (retval) {
-+ printk("%s: retval:%d\n", __FUNCTION__, retval);
-+ return retval;
-+ }
-+
-+ memcpy(fw->data + offset, buffer, count);
-+
-+ fw->size = max_t(size_t, offset + count, fw->size);
-+ file->f_pos += count;
-+ return count;
-+}
-+
-+static void
-+firmware_class_timeout(u_long data)
-+{
-+ struct firmware_priv *fw_priv = (struct firmware_priv *) data;
-+ fw_priv->abort = 1;
-+ wmb();
-+ complete(&fw_priv->completion);
-+}
-+static int
-+fw_setup_class_device(struct firmware_priv **fw_priv_p,
-+ const char *fw_name, const char *device)
-+{
-+ int retval;
-+ struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
-+ GFP_KERNEL);
-+ *fw_priv_p = fw_priv;
-+ if (!fw_priv) {
-+ retval = -ENOMEM;
-+ goto out;
-+ }
-+ memset(fw_priv, 0, sizeof (*fw_priv));
-+
-+ init_completion(&fw_priv->completion);
-+
-+ fw_priv->timeout.function = firmware_class_timeout;
-+ fw_priv->timeout.data = (u_long) fw_priv;
-+ init_timer(&fw_priv->timeout);
-+
-+ retval = -EAGAIN;
-+ fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
-+ if (!fw_priv->proc_dir)
-+ goto err_free_fw_priv;
-+
-+ fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
-+ fw_priv->proc_dir);
-+ if (!fw_priv->attr_data)
-+ goto err_remove_dir;
-+
-+ fw_priv->attr_data->read_proc = firmware_data_read;
-+ fw_priv->attr_data->write_proc = firmware_data_write;
-+ fw_priv->attr_data->data = fw_priv;
-+
-+ fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
-+ fw_priv->proc_dir);
-+ if (!fw_priv->attr_loading)
-+ goto err_remove_data;
-+
-+ fw_priv->attr_loading->read_proc = firmware_loading_show;
-+ fw_priv->attr_loading->write_proc = firmware_loading_store;
-+ fw_priv->attr_loading->data = fw_priv;
-+
-+ retval = 0;
-+ fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
-+ if (!fw_priv->fw) {
-+ printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
-+ __FUNCTION__);
-+ retval = -ENOMEM;
-+ goto err_remove_loading;
-+ }
-+ memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
-+
-+ goto out;
-+
-+err_remove_loading:
-+ remove_proc_entry("loading", fw_priv->proc_dir);
-+err_remove_data:
-+ remove_proc_entry("data", fw_priv->proc_dir);
-+err_remove_dir:
-+ remove_proc_entry(device, proc_dir);
-+err_free_fw_priv:
-+ kfree(fw_priv);
-+out:
-+ return retval;
-+}
-+static void
-+fw_remove_class_device(struct firmware_priv *fw_priv)
-+{
-+ remove_proc_entry("loading", fw_priv->proc_dir);
-+ remove_proc_entry("data", fw_priv->proc_dir);
-+ remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
-+}
-+
-+/**
-+ * request_firmware: - request firmware to hotplug and wait for it
-+ * Description:
-+ * @firmware will be used to return a firmware image by the name
-+ * of @name for device @device.
-+ *
-+ * Should be called from user context where sleeping is allowed.
-+ *
-+ * @name will be use as $FIRMWARE in the hotplug environment and
-+ * should be distinctive enough not to be confused with any other
-+ * firmware image for this or any other device.
-+ **/
-+int
-+request_firmware(const struct firmware **firmware, const char *name,
-+ const char *device)
-+{
-+ struct firmware_priv *fw_priv;
-+ int retval;
-+
-+ if (!firmware) {
-+ retval = -EINVAL;
-+ goto out;
-+ }
-+ *firmware = NULL;
-+
-+ retval = fw_setup_class_device(&fw_priv, name, device);
-+ if (retval)
-+ goto out;
-+
-+ retval = call_helper("add", name, device);
-+ if (retval)
-+ goto out;
-+ if (loading_timeout) {
-+ fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
-+ add_timer(&fw_priv->timeout);
-+ }
-+
-+ wait_for_completion(&fw_priv->completion);
-+
-+ del_timer(&fw_priv->timeout);
-+ fw_remove_class_device(fw_priv);
-+
-+ if (fw_priv->fw->size && !fw_priv->abort) {
-+ *firmware = fw_priv->fw;
-+ } else {
-+ retval = -ENOENT;
-+ vfree(fw_priv->fw->data);
-+ kfree(fw_priv->fw);
-+ }
-+out:
-+ kfree(fw_priv);
-+ return retval;
-+}
-+
-+void
-+release_firmware(const struct firmware *fw)
-+{
-+ if (fw) {
-+ vfree(fw->data);
-+ kfree(fw);
-+ }
-+}
-+
-+/**
-+ * register_firmware: - provide a firmware image for later usage
-+ *
-+ * Description:
-+ * Make sure that @data will be available by requesting firmware @name.
-+ *
-+ * Note: This will not be possible until some kind of persistence
-+ * is available.
-+ **/
-+void
-+register_firmware(const char *name, const u8 *data, size_t size)
-+{
-+ /* This is meaningless without firmware caching, so until we
-+ * decide if firmware caching is reasonable just leave it as a
-+ * noop */
-+}
-+
-+/* Async support */
-+struct firmware_work {
-+ struct tq_struct work;
-+ struct module *module;
-+ const char *name;
-+ const char *device;
-+ void *context;
-+ void (*cont)(const struct firmware *fw, void *context);
-+};
-+
-+static void
-+request_firmware_work_func(void *arg)
-+{
-+ struct firmware_work *fw_work = arg;
-+ const struct firmware *fw;
-+ if (!arg)
-+ return;
-+ request_firmware(&fw, fw_work->name, fw_work->device);
-+ fw_work->cont(fw, fw_work->context);
-+ release_firmware(fw);
-+ __MOD_DEC_USE_COUNT(fw_work->module);
-+ kfree(fw_work);
-+}
-+
-+/**
-+ * request_firmware_nowait:
-+ *
-+ * Description:
-+ * Asynchronous variant of request_firmware() for contexts where
-+ * it is not possible to sleep.
-+ *
-+ * @cont will be called asynchronously when the firmware request is over.
-+ *
-+ * @context will be passed over to @cont.
-+ *
-+ * @fw may be %NULL if firmware request fails.
-+ *
-+ **/
-+int
-+request_firmware_nowait(
-+ struct module *module,
-+ const char *name, const char *device, void *context,
-+ void (*cont)(const struct firmware *fw, void *context))
-+{
-+ struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
-+ GFP_ATOMIC);
-+ if (!fw_work)
-+ return -ENOMEM;
-+ if (!try_inc_mod_count(module)) {
-+ kfree(fw_work);
-+ return -EFAULT;
-+ }
-+
-+ *fw_work = (struct firmware_work) {
-+ .module = module,
-+ .name = name,
-+ .device = device,
-+ .context = context,
-+ .cont = cont,
-+ };
-+ INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
-+
-+ schedule_task(&fw_work->work);
-+ return 0;
-+}
-+
-+static int __init
-+firmware_class_init(void)
-+{
-+ proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
-+ if (!proc_dir)
-+ return -EAGAIN;
-+ proc_dir_timeout = create_proc_entry("timeout",
-+ 0644 | S_IFREG, proc_dir);
-+ if (!proc_dir_timeout) {
-+ remove_proc_entry("driver/firmware", NULL);
-+ return -EAGAIN;
-+ }
-+ proc_dir_timeout->read_proc = firmware_timeout_show;
-+ proc_dir_timeout->write_proc = firmware_timeout_store;
-+ return 0;
-+}
-+static void __exit
-+firmware_class_exit(void)
-+{
-+ remove_proc_entry("timeout", proc_dir);
-+ remove_proc_entry("driver/firmware", NULL);
-+}
-+
-+module_init(firmware_class_init);
-+module_exit(firmware_class_exit);
-+
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-diff -urN linux-2.4.18/net/bluetooth/Config.in linux-2.4.18-mh9/net/bluetooth/Config.in
---- linux-2.4.18/net/bluetooth/Config.in Tue Jun 12 04:15:27 2001
-+++ linux-2.4.18-mh9/net/bluetooth/Config.in Mon Aug 25 18:38:12 2003
-@@ -1,16 +1,22 @@
- #
--# Bluetooth configuration
-+# Bluetooth subsystem configuration
- #
-
- if [ "$CONFIG_NET" != "n" ]; then
-+
- mainmenu_option next_comment
- comment 'Bluetooth support'
- dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
-
- if [ "$CONFIG_BLUEZ" != "n" ]; then
- dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
-+ dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
-+ source net/bluetooth/rfcomm/Config.in
-+ source net/bluetooth/bnep/Config.in
-+ source net/bluetooth/cmtp/Config.in
- source drivers/bluetooth/Config.in
- fi
-+
- endmenu
- fi
-
-diff -urN linux-2.4.18/net/bluetooth/Makefile linux-2.4.18-mh9/net/bluetooth/Makefile
---- linux-2.4.18/net/bluetooth/Makefile Tue Jun 12 04:15:27 2001
-+++ linux-2.4.18-mh9/net/bluetooth/Makefile Mon Aug 25 18:38:12 2003
-@@ -1,20 +1,31 @@
- #
--# Makefile for the Bluetooth subsystem
-+# Makefile for the Linux Bluetooth subsystem
- #
--O_TARGET := bluetooth.o
-
--list-multi := hci.o l2cap.o
--export-objs := syms.o
--hci-objs := af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
--l2cap-objs := l2cap_core.o l2cap_proc.o
-+O_TARGET := bluetooth.o
-
--obj-$(CONFIG_BLUEZ) += hci.o
-+list-multi := bluez.o
-+export-objs := syms.o l2cap.o
-+
-+bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
-+
-+obj-$(CONFIG_BLUEZ) += bluez.o
- obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
-+obj-$(CONFIG_BLUEZ_SCO) += sco.o
-
--include $(TOPDIR)/Rules.make
-+subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
-+subdir-$(CONFIG_BLUEZ_BNEP) += bnep
-+subdir-$(CONFIG_BLUEZ_CMTP) += cmtp
-
--hci.o: $(hci-objs)
-- $(LD) -r -o $@ $(hci-objs)
-+ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
-+obj-y += rfcomm/rfcomm.o
-+endif
-+
-+ifeq ($(CONFIG_BLUEZ_BNEP),y)
-+obj-y += bnep/bnep.o
-+endif
-+
-+include $(TOPDIR)/Rules.make
-
--l2cap.o: $(l2cap-objs)
-- $(LD) -r -o $@ $(l2cap-objs)
-+bluez.o: $(bluez-objs)
-+ $(LD) -r -o $@ $(bluez-objs)
-diff -urN linux-2.4.18/net/bluetooth/af_bluetooth.c linux-2.4.18-mh9/net/bluetooth/af_bluetooth.c
---- linux-2.4.18/net/bluetooth/af_bluetooth.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/net/bluetooth/af_bluetooth.c Mon Aug 25 18:38:12 2003
-@@ -25,14 +25,15 @@
- /*
- * BlueZ Bluetooth address family and sockets.
- *
-- * $Id$
-+ * $Id$
- */
--#define VERSION "1.1"
-+#define VERSION "2.4"
-
- #include <linux/config.h>
- #include <linux/module.h>
-
- #include <linux/types.h>
-+#include <linux/list.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/major.h>
-@@ -40,6 +41,7 @@
- #include <linux/slab.h>
- #include <linux/skbuff.h>
- #include <linux/init.h>
-+#include <linux/poll.h>
- #include <linux/proc_fs.h>
- #include <net/sock.h>
-
-@@ -48,70 +50,79 @@
- #endif
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
-+
-+#ifndef AF_BLUETOOTH_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-
- /* Bluetooth sockets */
--static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
-+#define BLUEZ_MAX_PROTO 6
-+static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
-
- int bluez_sock_register(int proto, struct net_proto_family *ops)
- {
-- if (proto > BLUEZ_MAX_PROTO)
-+ if (proto >= BLUEZ_MAX_PROTO)
- return -EINVAL;
-
-- if (bluez_sock[proto])
-+ if (bluez_proto[proto])
- return -EEXIST;
-
-- bluez_sock[proto] = ops;
-+ bluez_proto[proto] = ops;
- return 0;
- }
-
- int bluez_sock_unregister(int proto)
- {
-- if (proto > BLUEZ_MAX_PROTO)
-+ if (proto >= BLUEZ_MAX_PROTO)
- return -EINVAL;
-
-- if (!bluez_sock[proto])
-+ if (!bluez_proto[proto])
- return -ENOENT;
-
-- bluez_sock[proto] = NULL;
-+ bluez_proto[proto] = NULL;
- return 0;
- }
-
- static int bluez_sock_create(struct socket *sock, int proto)
- {
-- if (proto > BLUEZ_MAX_PROTO)
-+ if (proto >= BLUEZ_MAX_PROTO)
- return -EINVAL;
-
- #if defined(CONFIG_KMOD)
-- if (!bluez_sock[proto]) {
-+ if (!bluez_proto[proto]) {
- char module_name[30];
- sprintf(module_name, "bt-proto-%d", proto);
- request_module(module_name);
- }
- #endif
-
-- if (!bluez_sock[proto])
-+ if (!bluez_proto[proto])
- return -ENOENT;
-
-- return bluez_sock[proto]->create(sock, proto);
-+ return bluez_proto[proto]->create(sock, proto);
-+}
-+
-+void bluez_sock_init(struct socket *sock, struct sock *sk)
-+{
-+ sock_init_data(sock, sk);
-+ INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
- }
-
- void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
- {
-- write_lock(&l->lock);
--
-+ write_lock_bh(&l->lock);
- sk->next = l->head;
- l->head = sk;
- sock_hold(sk);
--
-- write_unlock(&l->lock);
-+ write_unlock_bh(&l->lock);
- }
-
- void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
- {
- struct sock **skp;
-
-- write_lock(&l->lock);
-+ write_lock_bh(&l->lock);
- for (skp = &l->head; *skp; skp = &((*skp)->next)) {
- if (*skp == sk) {
- *skp = sk->next;
-@@ -119,7 +130,162 @@
- break;
- }
- }
-- write_unlock(&l->lock);
-+ write_unlock_bh(&l->lock);
-+}
-+
-+void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
-+{
-+ BT_DBG("parent %p, sk %p", parent, sk);
-+
-+ sock_hold(sk);
-+ list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
-+ bluez_pi(sk)->parent = parent;
-+ parent->ack_backlog++;
-+}
-+
-+static void bluez_accept_unlink(struct sock *sk)
-+{
-+ BT_DBG("sk %p state %d", sk, sk->state);
-+
-+ list_del_init(&bluez_pi(sk)->accept_q);
-+ bluez_pi(sk)->parent->ack_backlog--;
-+ bluez_pi(sk)->parent = NULL;
-+ sock_put(sk);
-+}
-+
-+struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
-+{
-+ struct list_head *p, *n;
-+ struct bluez_pinfo *pi;
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
-+ pi = list_entry(p, struct bluez_pinfo, accept_q);
-+ sk = bluez_sk(pi);
-+
-+ lock_sock(sk);
-+ if (sk->state == BT_CLOSED) {
-+ release_sock(sk);
-+ bluez_accept_unlink(sk);
-+ continue;
-+ }
-+
-+ if (sk->state == BT_CONNECTED || !newsock) {
-+ bluez_accept_unlink(sk);
-+ if (newsock)
-+ sock_graft(sk, newsock);
-+ release_sock(sk);
-+ return sk;
-+ }
-+ release_sock(sk);
-+ }
-+ return NULL;
-+}
-+
-+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
-+{
-+ int noblock = flags & MSG_DONTWAIT;
-+ struct sock *sk = sock->sk;
-+ struct sk_buff *skb;
-+ int copied, err;
-+
-+ BT_DBG("sock %p sk %p len %d", sock, sk, len);
-+
-+ if (flags & (MSG_OOB))
-+ return -EOPNOTSUPP;
-+
-+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
-+ if (sk->shutdown & RCV_SHUTDOWN)
-+ return 0;
-+ return err;
-+ }
-+
-+ msg->msg_namelen = 0;
-+
-+ copied = skb->len;
-+ if (len < copied) {
-+ msg->msg_flags |= MSG_TRUNC;
-+ copied = len;
-+ }
-+
-+ skb->h.raw = skb->data;
-+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-+
-+ skb_free_datagram(sk, skb);
-+
-+ return err ? : copied;
-+}
-+
-+unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
-+{
-+ struct sock *sk = sock->sk;
-+ unsigned int mask;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ poll_wait(file, sk->sleep, wait);
-+ mask = 0;
-+
-+ if (sk->err || !skb_queue_empty(&sk->error_queue))
-+ mask |= POLLERR;
-+
-+ if (sk->shutdown == SHUTDOWN_MASK)
-+ mask |= POLLHUP;
-+
-+ if (!skb_queue_empty(&sk->receive_queue) ||
-+ !list_empty(&bluez_pi(sk)->accept_q) ||
-+ (sk->shutdown & RCV_SHUTDOWN))
-+ mask |= POLLIN | POLLRDNORM;
-+
-+ if (sk->state == BT_CLOSED)
-+ mask |= POLLHUP;
-+
-+ if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
-+ return mask;
-+
-+ if (sock_writeable(sk))
-+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-+ else
-+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-+
-+ return mask;
-+}
-+
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ add_wait_queue(sk->sleep, &wait);
-+ while (sk->state != state) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->err) {
-+ err = sock_error(sk);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+ return err;
- }
-
- struct net_proto_family bluez_sock_family_ops =
-@@ -129,9 +295,9 @@
-
- int bluez_init(void)
- {
-- INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+ BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
- proc_mkdir("bluetooth", NULL);
-
-@@ -164,5 +330,6 @@
- module_exit(bluez_cleanup);
-
- MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
-+MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
-+MODULE_LICENSE("GPL");
- #endif
-diff -urN linux-2.4.18/net/bluetooth/bnep/Config.in linux-2.4.18-mh9/net/bluetooth/bnep/Config.in
---- linux-2.4.18/net/bluetooth/bnep/Config.in Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/Config.in Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,11 @@
-+#
-+# Bluetooth BNEP layer configuration
-+#
-+
-+dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
-+
-+if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
-+ bool ' Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
-+ bool ' Protocol filter support' CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+fi
-+
-diff -urN linux-2.4.18/net/bluetooth/bnep/Makefile linux-2.4.18-mh9/net/bluetooth/bnep/Makefile
---- linux-2.4.18/net/bluetooth/bnep/Makefile Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/Makefile Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth BNEP layer
-+#
-+
-+O_TARGET := bnep.o
-+
-+obj-y := core.o sock.o netdev.o crc32.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/bnep/bnep.h linux-2.4.18-mh9/net/bluetooth/bnep/bnep.h
---- linux-2.4.18/net/bluetooth/bnep/bnep.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/bnep.h Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,185 @@
-+/*
-+ BNEP protocol definition for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License, version 2, as
-+ published by the Free Software Foundation.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#ifndef _BNEP_H
-+#define _BNEP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+#include "crc32.h"
-+
-+// Limits
-+#define BNEP_MAX_PROTO_FILTERS 5
-+#define BNEP_MAX_MULTICAST_FILTERS 20
-+
-+// UUIDs
-+#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
-+#define BNEP_UUID16 0x02
-+#define BNEP_UUID32 0x04
-+#define BNEP_UUID128 0x16
-+
-+#define BNEP_SVC_PANU 0x1115
-+#define BNEP_SVC_NAP 0x1116
-+#define BNEP_SVC_GN 0x1117
-+
-+// Packet types
-+#define BNEP_GENERAL 0x00
-+#define BNEP_CONTROL 0x01
-+#define BNEP_COMPRESSED 0x02
-+#define BNEP_COMPRESSED_SRC_ONLY 0x03
-+#define BNEP_COMPRESSED_DST_ONLY 0x04
-+
-+// Control types
-+#define BNEP_CMD_NOT_UNDERSTOOD 0x00
-+#define BNEP_SETUP_CONN_REQ 0x01
-+#define BNEP_SETUP_CONN_RSP 0x02
-+#define BNEP_FILTER_NET_TYPE_SET 0x03
-+#define BNEP_FILTER_NET_TYPE_RSP 0x04
-+#define BNEP_FILTER_MULTI_ADDR_SET 0x05
-+#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
-+
-+// Extension types
-+#define BNEP_EXT_CONTROL 0x00
-+
-+// Response messages
-+#define BNEP_SUCCESS 0x00
-+
-+#define BNEP_CONN_INVALID_DST 0x01
-+#define BNEP_CONN_INVALID_SRC 0x02
-+#define BNEP_CONN_INVALID_SVC 0x03
-+#define BNEP_CONN_NOT_ALLOWED 0x04
-+
-+#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
-+#define BNEP_FILTER_INVALID_RANGE 0x02
-+#define BNEP_FILTER_INVALID_MCADDR 0x02
-+#define BNEP_FILTER_LIMIT_REACHED 0x03
-+#define BNEP_FILTER_DENIED_SECURITY 0x04
-+
-+// L2CAP settings
-+#define BNEP_MTU 1691
-+#define BNEP_PSM 0x0f
-+#define BNEP_FLUSH_TO 0xffff
-+#define BNEP_CONNECT_TO 15
-+#define BNEP_FILTER_TO 15
-+
-+// Headers
-+#define BNEP_TYPE_MASK 0x7f
-+#define BNEP_EXT_HEADER 0x80
-+
-+struct bnep_setup_conn_req {
-+ __u8 type;
-+ __u8 ctrl;
-+ __u8 uuid_size;
-+ __u8 service[0];
-+} __attribute__((packed));
-+
-+struct bnep_set_filter_req {
-+ __u8 type;
-+ __u8 ctrl;
-+ __u16 len;
-+ __u8 list[0];
-+} __attribute__((packed));
-+
-+struct bnep_control_rsp {
-+ __u8 type;
-+ __u8 ctrl;
-+ __u16 resp;
-+} __attribute__((packed));
-+
-+struct bnep_ext_hdr {
-+ __u8 type;
-+ __u8 len;
-+ __u8 data[0];
-+} __attribute__((packed));
-+
-+/* BNEP ioctl defines */
-+#define BNEPCONNADD _IOW('B', 200, int)
-+#define BNEPCONNDEL _IOW('B', 201, int)
-+#define BNEPGETCONNLIST _IOR('B', 210, int)
-+#define BNEPGETCONNINFO _IOR('B', 211, int)
-+
-+struct bnep_connadd_req {
-+ int sock; // Connected socket
-+ __u32 flags;
-+ __u16 role;
-+ char device[16]; // Name of the Ethernet device
-+};
-+
-+struct bnep_conndel_req {
-+ __u32 flags;
-+ __u8 dst[ETH_ALEN];
-+};
-+
-+struct bnep_conninfo {
-+ __u32 flags;
-+ __u16 role;
-+ __u16 state;
-+ __u8 dst[ETH_ALEN];
-+ char device[16];
-+};
-+
-+struct bnep_connlist_req {
-+ __u32 cnum;
-+ struct bnep_conninfo *ci;
-+};
-+
-+struct bnep_proto_filter {
-+ __u16 start;
-+ __u16 end;
-+};
-+
-+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
-+int bnep_del_connection(struct bnep_conndel_req *req);
-+int bnep_get_connlist(struct bnep_connlist_req *req);
-+int bnep_get_conninfo(struct bnep_conninfo *ci);
-+
-+// BNEP sessions
-+struct bnep_session {
-+ struct list_head list;
-+
-+ unsigned int role;
-+ unsigned long state;
-+ unsigned long flags;
-+ atomic_t killed;
-+
-+ struct ethhdr eh;
-+ struct msghdr msg;
-+
-+ struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
-+ u64 mc_filter;
-+
-+ struct socket *sock;
-+ struct net_device dev;
-+ struct net_device_stats stats;
-+};
-+
-+int bnep_net_init(struct net_device *dev);
-+int bnep_sock_init(void);
-+int bnep_sock_cleanup(void);
-+
-+static inline int bnep_mc_hash(__u8 *addr)
-+{
-+ return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
-+}
-+
-+#endif
-diff -urN linux-2.4.18/net/bluetooth/bnep/core.c linux-2.4.18-mh9/net/bluetooth/bnep/core.c
---- linux-2.4.18/net/bluetooth/bnep/core.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/core.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,708 @@
-+/*
-+ BNEP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2001-2002 Inventel Systemes
-+ Written 2001-2002 by
-+ Clément Moreau <clement.moreau@inventel.fr>
-+ David Libault <david.libault@inventel.fr>
-+
-+ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/init.h>
-+#include <linux/wait.h>
-+#include <linux/errno.h>
-+#include <linux/smp_lock.h>
-+#include <linux/net.h>
-+#include <net/sock.h>
-+
-+#include <linux/socket.h>
-+#include <linux/file.h>
-+
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.1"
-+
-+static LIST_HEAD(bnep_session_list);
-+static DECLARE_RWSEM(bnep_session_sem);
-+
-+static struct bnep_session *__bnep_get_session(u8 *dst)
-+{
-+ struct bnep_session *s;
-+ struct list_head *p;
-+
-+ BT_DBG("");
-+
-+ list_for_each(p, &bnep_session_list) {
-+ s = list_entry(p, struct bnep_session, list);
-+ if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
-+ return s;
-+ }
-+ return NULL;
-+}
-+
-+static void __bnep_link_session(struct bnep_session *s)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&s->list, &bnep_session_list);
-+}
-+
-+static void __bnep_unlink_session(struct bnep_session *s)
-+{
-+ list_del(&s->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static int bnep_send(struct bnep_session *s, void *data, size_t len)
-+{
-+ struct socket *sock = s->sock;
-+ struct iovec iv = { data, len };
-+ s->msg.msg_iov = &iv;
-+ s->msg.msg_iovlen = 1;
-+ return sock->ops->sendmsg(sock, &s->msg, len, NULL);
-+}
-+
-+static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
-+{
-+ struct bnep_control_rsp rsp;
-+ rsp.type = BNEP_CONTROL;
-+ rsp.ctrl = ctrl;
-+ rsp.resp = htons(resp);
-+ return bnep_send(s, &rsp, sizeof(rsp));
-+}
-+
-+static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
-+{
-+ int n;
-+
-+ if (len < 2)
-+ return -EILSEQ;
-+
-+ n = ntohs(get_unaligned(data));
-+ data++; len -= 2;
-+
-+ if (len < n)
-+ return -EILSEQ;
-+
-+ BT_DBG("filter len %d", n);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ n /= 4;
-+ if (n <= BNEP_MAX_PROTO_FILTERS) {
-+ struct bnep_proto_filter *f = s->proto_filter;
-+ int i;
-+
-+ for (i = 0; i < n; i++) {
-+ f[i].start = get_unaligned(data++);
-+ f[i].end = get_unaligned(data++);
-+
-+ BT_DBG("proto filter start %d end %d",
-+ f[i].start, f[i].end);
-+ }
-+ if (i < BNEP_MAX_PROTO_FILTERS)
-+ memset(f + i, 0, sizeof(*f));
-+
-+ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
-+ } else {
-+ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
-+ }
-+#else
-+ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-+#endif
-+ return 0;
-+}
-+
-+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
-+{
-+ int n;
-+
-+ if (len < 2)
-+ return -EILSEQ;
-+
-+ n = ntohs(get_unaligned((u16 *) data));
-+ data += 2; len -= 2;
-+
-+ if (len < n)
-+ return -EILSEQ;
-+
-+ BT_DBG("filter len %d", n);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ n /= (ETH_ALEN * 2);
-+
-+ if (n > 0) {
-+ s->mc_filter = 0;
-+
-+ /* Always send broadcast */
-+ set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
-+
-+ /* Add address ranges to the multicast hash */
-+ for (; n > 0; n--) {
-+ u8 a1[6], *a2;
-+
-+ memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
-+ a2 = data; data += ETH_ALEN;
-+
-+ BT_DBG("mc filter %s -> %s",
-+ batostr((void *) a1), batostr((void *) a2));
-+
-+ #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
-+
-+ /* Iterate from a1 to a2 */
-+ set_bit(bnep_mc_hash(a1), &s->mc_filter);
-+ while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
-+ INCA(a1);
-+ set_bit(bnep_mc_hash(a1), &s->mc_filter);
-+ }
-+ }
-+ }
-+
-+ BT_DBG("mc filter hash 0x%llx", s->mc_filter);
-+
-+ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
-+#else
-+ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-+#endif
-+ return 0;
-+}
-+
-+static int bnep_rx_control(struct bnep_session *s, void *data, int len)
-+{
-+ u8 cmd = *(u8 *)data;
-+ int err = 0;
-+
-+ data++; len--;
-+
-+ switch (cmd) {
-+ case BNEP_CMD_NOT_UNDERSTOOD:
-+ case BNEP_SETUP_CONN_REQ:
-+ case BNEP_SETUP_CONN_RSP:
-+ case BNEP_FILTER_NET_TYPE_RSP:
-+ case BNEP_FILTER_MULTI_ADDR_RSP:
-+ /* Ignore these for now */
-+ break;
-+
-+ case BNEP_FILTER_NET_TYPE_SET:
-+ err = bnep_ctrl_set_netfilter(s, data, len);
-+ break;
-+
-+ case BNEP_FILTER_MULTI_ADDR_SET:
-+ err = bnep_ctrl_set_mcfilter(s, data, len);
-+ break;
-+
-+ default: {
-+ u8 pkt[3];
-+ pkt[0] = BNEP_CONTROL;
-+ pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
-+ pkt[2] = cmd;
-+ bnep_send(s, pkt, sizeof(pkt));
-+ }
-+ break;
-+ }
-+
-+ return err;
-+}
-+
-+static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
-+{
-+ struct bnep_ext_hdr *h;
-+ int err = 0;
-+
-+ do {
-+ h = (void *) skb->data;
-+ if (!skb_pull(skb, sizeof(*h))) {
-+ err = -EILSEQ;
-+ break;
-+ }
-+
-+ BT_DBG("type 0x%x len %d", h->type, h->len);
-+
-+ switch (h->type & BNEP_TYPE_MASK) {
-+ case BNEP_EXT_CONTROL:
-+ bnep_rx_control(s, skb->data, skb->len);
-+ break;
-+
-+ default:
-+ /* Unknown extension, skip it. */
-+ break;
-+ }
-+
-+ if (!skb_pull(skb, h->len)) {
-+ err = -EILSEQ;
-+ break;
-+ }
-+ } while (!err && (h->type & BNEP_EXT_HEADER));
-+
-+ return err;
-+}
-+
-+static u8 __bnep_rx_hlen[] = {
-+ ETH_HLEN, /* BNEP_GENERAL */
-+ 0, /* BNEP_CONTROL */
-+ 2, /* BNEP_COMPRESSED */
-+ ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
-+ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
-+};
-+#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1)
-+
-+static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
-+{
-+ struct net_device *dev = &s->dev;
-+ struct sk_buff *nskb;
-+ u8 type;
-+
-+ dev->last_rx = jiffies;
-+ s->stats.rx_bytes += skb->len;
-+
-+ type = *(u8 *) skb->data; skb_pull(skb, 1);
-+
-+ if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
-+ goto badframe;
-+
-+ if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
-+ bnep_rx_control(s, skb->data, skb->len);
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+
-+ skb->mac.raw = skb->data;
-+
-+ /* Verify and pull out header */
-+ if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
-+ goto badframe;
-+
-+ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
-+
-+ if (type & BNEP_EXT_HEADER) {
-+ if (bnep_rx_extension(s, skb) < 0)
-+ goto badframe;
-+ }
-+
-+ /* Strip 802.1p header */
-+ if (ntohs(s->eh.h_proto) == 0x8100) {
-+ if (!skb_pull(skb, 4))
-+ goto badframe;
-+ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
-+ }
-+
-+ /* We have to alloc new skb and copy data here :(. Because original skb
-+ * may not be modified and because of the alignment requirements. */
-+ nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
-+ if (!nskb) {
-+ s->stats.rx_dropped++;
-+ kfree_skb(skb);
-+ return -ENOMEM;
-+ }
-+ skb_reserve(nskb, 2);
-+
-+ /* Decompress header and construct ether frame */
-+ switch (type & BNEP_TYPE_MASK) {
-+ case BNEP_COMPRESSED:
-+ memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
-+ break;
-+
-+ case BNEP_COMPRESSED_SRC_ONLY:
-+ memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
-+ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-+ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
-+ break;
-+
-+ case BNEP_COMPRESSED_DST_ONLY:
-+ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-+ memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
-+ break;
-+
-+ case BNEP_GENERAL:
-+ memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
-+ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
-+ break;
-+ }
-+
-+ memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
-+ kfree_skb(skb);
-+
-+ s->stats.rx_packets++;
-+ nskb->dev = dev;
-+ nskb->ip_summed = CHECKSUM_UNNECESSARY;
-+ nskb->protocol = eth_type_trans(nskb, dev);
-+ netif_rx_ni(nskb);
-+ return 0;
-+
-+badframe:
-+ s->stats.rx_errors++;
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static u8 __bnep_tx_types[] = {
-+ BNEP_GENERAL,
-+ BNEP_COMPRESSED_SRC_ONLY,
-+ BNEP_COMPRESSED_DST_ONLY,
-+ BNEP_COMPRESSED
-+};
-+
-+static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
-+{
-+ struct ethhdr *eh = (void *) skb->data;
-+ struct socket *sock = s->sock;
-+ struct iovec iv[3];
-+ int len = 0, il = 0;
-+ u8 type = 0;
-+
-+ BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
-+
-+ if (!skb->dev) {
-+ /* Control frame sent by us */
-+ goto send;
-+ }
-+
-+ iv[il++] = (struct iovec) { &type, 1 };
-+ len++;
-+
-+ if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
-+ type |= 0x01;
-+
-+ if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
-+ type |= 0x02;
-+
-+ if (type)
-+ skb_pull(skb, ETH_ALEN * 2);
-+
-+ type = __bnep_tx_types[type];
-+ switch (type) {
-+ case BNEP_COMPRESSED_SRC_ONLY:
-+ iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
-+ len += ETH_ALEN;
-+ break;
-+
-+ case BNEP_COMPRESSED_DST_ONLY:
-+ iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
-+ len += ETH_ALEN;
-+ break;
-+ }
-+
-+send:
-+ iv[il++] = (struct iovec) { skb->data, skb->len };
-+ len += skb->len;
-+
-+ /* FIXME: linearize skb */
-+
-+ s->msg.msg_iov = iv;
-+ s->msg.msg_iovlen = il;
-+ len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
-+ kfree_skb(skb);
-+
-+ if (len > 0) {
-+ s->stats.tx_bytes += len;
-+ s->stats.tx_packets++;
-+ return 0;
-+ }
-+
-+ return len;
-+}
-+
-+static int bnep_session(void *arg)
-+{
-+ struct bnep_session *s = arg;
-+ struct net_device *dev = &s->dev;
-+ struct sock *sk = s->sock->sk;
-+ struct sk_buff *skb;
-+ wait_queue_t wait;
-+
-+ BT_DBG("");
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "kbnepd %s", dev->name);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&wait, current);
-+ add_wait_queue(sk->sleep, &wait);
-+ while (!atomic_read(&s->killed)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ // RX
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ bnep_rx_frame(s, skb);
-+ }
-+
-+ if (sk->state != BT_CONNECTED)
-+ break;
-+
-+ // TX
-+ while ((skb = skb_dequeue(&sk->write_queue)))
-+ if (bnep_tx_frame(s, skb))
-+ break;
-+ netif_wake_queue(dev);
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ /* Cleanup session */
-+ down_write(&bnep_session_sem);
-+
-+ /* Delete network device */
-+ unregister_netdev(dev);
-+
-+ /* Release the socket */
-+ fput(s->sock->file);
-+
-+ __bnep_unlink_session(s);
-+
-+ up_write(&bnep_session_sem);
-+ kfree(s);
-+ return 0;
-+}
-+
-+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
-+{
-+ struct net_device *dev;
-+ struct bnep_session *s, *ss;
-+ u8 dst[ETH_ALEN], src[ETH_ALEN];
-+ int err;
-+
-+ BT_DBG("");
-+
-+ baswap((void *) dst, &bluez_pi(sock->sk)->dst);
-+ baswap((void *) src, &bluez_pi(sock->sk)->src);
-+
-+ s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
-+ if (!s)
-+ return -ENOMEM;
-+ memset(s, 0, sizeof(struct bnep_session));
-+
-+ down_write(&bnep_session_sem);
-+
-+ ss = __bnep_get_session(dst);
-+ if (ss && ss->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ dev = &s->dev;
-+
-+ if (*req->device)
-+ strcpy(dev->name, req->device);
-+ else
-+ strcpy(dev->name, "bnep%d");
-+
-+ memset(dev->broadcast, 0xff, ETH_ALEN);
-+
-+ /* This is rx header therefor addresses are swaped.
-+ * ie eh.h_dest is our local address. */
-+ memcpy(s->eh.h_dest, &src, ETH_ALEN);
-+ memcpy(s->eh.h_source, &dst, ETH_ALEN);
-+
-+ s->sock = sock;
-+ s->role = req->role;
-+ s->state = BT_CONNECTED;
-+
-+ s->msg.msg_flags = MSG_NOSIGNAL;
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ /* Set default mc filter */
-+ set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ /* Set default protocol filter */
-+
-+ /* (IPv4, ARP) */
-+ s->proto_filter[0].start = htons(0x0800);
-+ s->proto_filter[0].end = htons(0x0806);
-+ /* (RARP, AppleTalk) */
-+ s->proto_filter[1].start = htons(0x8035);
-+ s->proto_filter[1].end = htons(0x80F3);
-+ /* (IPX, IPv6) */
-+ s->proto_filter[2].start = htons(0x8137);
-+ s->proto_filter[2].end = htons(0x86DD);
-+#endif
-+
-+ dev->init = bnep_net_init;
-+ dev->priv = s;
-+ err = register_netdev(dev);
-+ if (err) {
-+ goto failed;
-+ }
-+
-+ __bnep_link_session(s);
-+
-+ err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (err < 0) {
-+ /* Session thread start failed, gotta cleanup. */
-+ unregister_netdev(dev);
-+ __bnep_unlink_session(s);
-+ goto failed;
-+ }
-+
-+ up_write(&bnep_session_sem);
-+ strcpy(req->device, dev->name);
-+ return 0;
-+
-+failed:
-+ up_write(&bnep_session_sem);
-+ kfree(s);
-+ return err;
-+}
-+
-+int bnep_del_connection(struct bnep_conndel_req *req)
-+{
-+ struct bnep_session *s;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&bnep_session_sem);
-+
-+ s = __bnep_get_session(req->dst);
-+ if (s) {
-+ /* Wakeup user-space which is polling for socket errors.
-+ * This is temporary hack untill we have shutdown in L2CAP */
-+ s->sock->sk->err = EUNATCH;
-+
-+ /* Kill session thread */
-+ atomic_inc(&s->killed);
-+ wake_up_interruptible(s->sock->sk->sleep);
-+ } else
-+ err = -ENOENT;
-+
-+ up_read(&bnep_session_sem);
-+ return err;
-+}
-+
-+static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
-+{
-+ memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
-+ strcpy(ci->device, s->dev.name);
-+ ci->flags = s->flags;
-+ ci->state = s->state;
-+ ci->role = s->role;
-+}
-+
-+int bnep_get_connlist(struct bnep_connlist_req *req)
-+{
-+ struct list_head *p;
-+ int err = 0, n = 0;
-+
-+ down_read(&bnep_session_sem);
-+
-+ list_for_each(p, &bnep_session_list) {
-+ struct bnep_session *s;
-+ struct bnep_conninfo ci;
-+
-+ s = list_entry(p, struct bnep_session, list);
-+
-+ __bnep_copy_ci(&ci, s);
-+
-+ if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (++n >= req->cnum)
-+ break;
-+
-+ req->ci++;
-+ }
-+ req->cnum = n;
-+
-+ up_read(&bnep_session_sem);
-+ return err;
-+}
-+
-+int bnep_get_conninfo(struct bnep_conninfo *ci)
-+{
-+ struct bnep_session *s;
-+ int err = 0;
-+
-+ down_read(&bnep_session_sem);
-+
-+ s = __bnep_get_session(ci->dst);
-+ if (s)
-+ __bnep_copy_ci(ci, s);
-+ else
-+ err = -ENOENT;
-+
-+ up_read(&bnep_session_sem);
-+ return err;
-+}
-+
-+static int __init bnep_init_module(void)
-+{
-+ l2cap_load();
-+
-+ bnep_crc32_init();
-+ bnep_sock_init();
-+
-+ BT_INFO("BlueZ BNEP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
-+ BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
-+ BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
-+ BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
-+
-+ return 0;
-+}
-+
-+static void __exit bnep_cleanup_module(void)
-+{
-+ bnep_sock_cleanup();
-+ bnep_crc32_cleanup();
-+}
-+
-+module_init(bnep_init_module);
-+module_exit(bnep_cleanup_module);
-+
-+MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
-+MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.c linux-2.4.18-mh9/net/bluetooth/bnep/crc32.c
---- linux-2.4.18/net/bluetooth/bnep/crc32.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/crc32.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,59 @@
-+/*
-+ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
-+ *
-+ * FIXME: Remove in 2.5
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <asm/atomic.h>
-+
-+#include "crc32.h"
-+
-+#define CRCPOLY_BE 0x04c11db7
-+#define CRC_BE_BITS 8
-+
-+static u32 *bnep_crc32_table;
-+
-+/*
-+ * This code is in the public domain; copyright abandoned.
-+ * Liability for non-performance of this code is limited to the amount
-+ * you paid for it. Since it is distributed for free, your refund will
-+ * be very very small. If it breaks, you get to keep both pieces.
-+ */
-+u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
-+{
-+ while (len--)
-+ crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
-+
-+ return crc;
-+}
-+
-+int __init bnep_crc32_init(void)
-+{
-+ unsigned i, j;
-+ u32 crc = 0x80000000;
-+
-+ bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
-+ if (!bnep_crc32_table)
-+ return -ENOMEM;
-+
-+ bnep_crc32_table[0] = 0;
-+
-+ for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
-+ crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
-+ for (j = 0; j < i; j++)
-+ bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
-+ }
-+ return 0;
-+}
-+
-+void __exit bnep_crc32_cleanup(void)
-+{
-+ if (bnep_crc32_table)
-+ kfree(bnep_crc32_table);
-+ bnep_crc32_table = NULL;
-+}
-diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.h linux-2.4.18-mh9/net/bluetooth/bnep/crc32.h
---- linux-2.4.18/net/bluetooth/bnep/crc32.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/crc32.h Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,10 @@
-+/*
-+ * crc32.h
-+ * See crc32.c for license and changes
-+ *
-+ * FIXME: Remove in 2.5
-+ */
-+
-+int bnep_crc32_init(void);
-+void bnep_crc32_cleanup(void);
-+u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len);
-diff -urN linux-2.4.18/net/bluetooth/bnep/netdev.c linux-2.4.18-mh9/net/bluetooth/bnep/netdev.c
---- linux-2.4.18/net/bluetooth/bnep/netdev.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/netdev.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,254 @@
-+/*
-+ BNEP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2001-2002 Inventel Systemes
-+ Written 2001-2002 by
-+ Clément Moreau <clement.moreau@inventel.fr>
-+ David Libault <david.libault@inventel.fr>
-+
-+ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/socket.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/wait.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+#define BNEP_TX_QUEUE_LEN 20
-+
-+static int bnep_net_open(struct net_device *dev)
-+{
-+ netif_start_queue(dev);
-+ return 0;
-+}
-+
-+static int bnep_net_close(struct net_device *dev)
-+{
-+ netif_stop_queue(dev);
-+ return 0;
-+}
-+
-+static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
-+{
-+ struct bnep_session *s = dev->priv;
-+ return &s->stats;
-+}
-+
-+static void bnep_net_set_mc_list(struct net_device *dev)
-+{
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ struct bnep_session *s = dev->priv;
-+ struct sock *sk = s->sock->sk;
-+ struct bnep_set_filter_req *r;
-+ struct sk_buff *skb;
-+ int size;
-+
-+ BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
-+
-+ size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
-+ skb = alloc_skb(size, GFP_ATOMIC);
-+ if (!skb) {
-+ BT_ERR("%s Multicast list allocation failed", dev->name);
-+ return;
-+ }
-+
-+ r = (void *) skb->data;
-+ __skb_put(skb, sizeof(*r));
-+
-+ r->type = BNEP_CONTROL;
-+ r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
-+
-+ if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
-+ u8 start[ETH_ALEN] = { 0x01 };
-+
-+ /* Request all addresses */
-+ memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
-+ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+ r->len = htons(ETH_ALEN * 2);
-+ } else {
-+ struct dev_mc_list *dmi = dev->mc_list;
-+ int i, len = skb->len;
-+
-+ if (dev->flags & IFF_BROADCAST) {
-+ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+ }
-+
-+ /* FIXME: We should group addresses here. */
-+
-+ for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
-+ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-+ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-+ dmi = dmi->next;
-+ }
-+ r->len = htons(skb->len - len);
-+ }
-+
-+ skb_queue_tail(&sk->write_queue, skb);
-+ wake_up_interruptible(sk->sleep);
-+#endif
-+}
-+
-+static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
-+{
-+ BT_DBG("%s", dev->name);
-+ return 0;
-+}
-+
-+static void bnep_net_timeout(struct net_device *dev)
-+{
-+ BT_DBG("net_timeout");
-+ netif_wake_queue(dev);
-+}
-+
-+static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-+{
-+ return -EINVAL;
-+}
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
-+{
-+ struct ethhdr *eh = (void *) skb->data;
-+
-+ if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
-+ BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb,
-+ eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
-+ eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
-+ return 1;
-+ }
-+ return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+/* Determine ether protocol. Based on eth_type_trans. */
-+static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
-+{
-+ struct ethhdr *eh = (void *) skb->data;
-+
-+ if (ntohs(eh->h_proto) >= 1536)
-+ return eh->h_proto;
-+
-+ if (get_unaligned((u16 *) skb->data) == 0xFFFF)
-+ return htons(ETH_P_802_3);
-+
-+ return htons(ETH_P_802_2);
-+}
-+
-+static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
-+{
-+ u16 proto = bnep_net_eth_proto(skb);
-+ struct bnep_proto_filter *f = s->proto_filter;
-+ int i;
-+
-+ for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
-+ if (proto >= f[i].start && proto <= f[i].end)
-+ return 0;
-+ }
-+
-+ BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
-+ return 1;
-+}
-+#endif
-+
-+static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct bnep_session *s = dev->priv;
-+ struct sock *sk = s->sock->sk;
-+
-+ BT_DBG("skb %p, dev %p", skb, dev);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+ if (bnep_net_mc_filter(skb, s)) {
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+ if (bnep_net_proto_filter(skb, s)) {
-+ kfree_skb(skb);
-+ return 0;
-+ }
-+#endif
-+
-+ /*
-+ * We cannot send L2CAP packets from here as we are potentially in a bh.
-+ * So we have to queue them and wake up session thread which is sleeping
-+ * on the sk->sleep.
-+ */
-+ dev->trans_start = jiffies;
-+ skb_queue_tail(&sk->write_queue, skb);
-+ wake_up_interruptible(sk->sleep);
-+
-+ if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
-+ BT_DBG("tx queue is full");
-+
-+ /* Stop queuing.
-+ * Session thread will do netif_wake_queue() */
-+ netif_stop_queue(dev);
-+ }
-+
-+ return 0;
-+}
-+
-+int bnep_net_init(struct net_device *dev)
-+{
-+ struct bnep_session *s = dev->priv;
-+
-+ memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
-+ dev->addr_len = ETH_ALEN;
-+
-+ ether_setup(dev);
-+
-+ dev->open = bnep_net_open;
-+ dev->stop = bnep_net_close;
-+ dev->hard_start_xmit = bnep_net_xmit;
-+ dev->get_stats = bnep_net_get_stats;
-+ dev->do_ioctl = bnep_net_ioctl;
-+ dev->set_mac_address = bnep_net_set_mac_addr;
-+ dev->set_multicast_list = bnep_net_set_mc_list;
-+
-+ dev->watchdog_timeo = HZ * 2;
-+ dev->tx_timeout = bnep_net_timeout;
-+
-+ return 0;
-+}
-diff -urN linux-2.4.18/net/bluetooth/bnep/sock.c linux-2.4.18-mh9/net/bluetooth/bnep/sock.c
---- linux-2.4.18/net/bluetooth/bnep/sock.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/bnep/sock.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,238 @@
-+/*
-+ BNEP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2001-2002 Inventel Systemes
-+ Written 2001-2002 by
-+ David Libault <david.libault@inventel.fr>
-+
-+ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static inline struct socket *socki_lookup(struct inode *inode)
-+{
-+ return &inode->u.socket_i;
-+}
-+
-+static struct socket *sockfd_lookup(int fd, int *err)
-+{
-+ struct file *file;
-+ struct inode *inode;
-+ struct socket *sock;
-+
-+ if (!(file = fget(fd))) {
-+ *err = -EBADF;
-+ return NULL;
-+ }
-+
-+ inode = file->f_dentry->d_inode;
-+ if (!inode->i_sock || !(sock = socki_lookup(inode))) {
-+ *err = -ENOTSOCK;
-+ fput(file);
-+ return NULL;
-+ }
-+
-+ if (sock->file != file) {
-+ printk(KERN_ERR "socki_lookup: socket file changed!\n");
-+ sock->file = file;
-+ }
-+ return sock;
-+}
-+
-+static int bnep_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct bnep_connlist_req cl;
-+ struct bnep_connadd_req ca;
-+ struct bnep_conndel_req cd;
-+ struct bnep_conninfo ci;
-+ struct socket *nsock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case BNEPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ nsock = sockfd_lookup(ca.sock, &err);
-+ if (!nsock)
-+ return err;
-+
-+ if (nsock->sk->state != BT_CONNECTED)
-+ return -EBADFD;
-+
-+ err = bnep_add_connection(&ca, nsock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else
-+ fput(nsock->file);
-+
-+ return err;
-+
-+ case BNEPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return bnep_del_connection(&cd);
-+
-+ case BNEPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = bnep_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case BNEPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = bnep_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct proto_ops bnep_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: bnep_sock_release,
-+ ioctl: bnep_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int bnep_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &bnep_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family bnep_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: bnep_sock_create
-+};
-+
-+int bnep_sock_init(void)
-+{
-+ bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
-+ return 0;
-+}
-+
-+int bnep_sock_cleanup(void)
-+{
-+ if (bluez_sock_unregister(BTPROTO_BNEP))
-+ BT_ERR("Can't unregister BNEP socket");
-+ return 0;
-+}
-diff -urN linux-2.4.18/net/bluetooth/cmtp/Config.in linux-2.4.18-mh9/net/bluetooth/cmtp/Config.in
---- linux-2.4.18/net/bluetooth/cmtp/Config.in Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/cmtp/Config.in Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,7 @@
-+#
-+# Bluetooth CMTP layer configuration
-+#
-+
-+if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then
-+ dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP
-+fi
-diff -urN linux-2.4.18/net/bluetooth/cmtp/Makefile linux-2.4.18-mh9/net/bluetooth/cmtp/Makefile
---- linux-2.4.18/net/bluetooth/cmtp/Makefile Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/cmtp/Makefile Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth CMTP layer
-+#
-+
-+O_TARGET := cmtp.o
-+
-+obj-y := core.o sock.o capi.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/cmtp/capi.c linux-2.4.18-mh9/net/bluetooth/cmtp/capi.c
---- linux-2.4.18/net/bluetooth/cmtp/capi.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/cmtp/capi.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,707 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <net/sock.h>
-+
-+#include <linux/capi.h>
-+
-+#include "../drivers/isdn/avmb1/capilli.h"
-+#include "../drivers/isdn/avmb1/capicmd.h"
-+#include "../drivers/isdn/avmb1/capiutil.h"
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define REVISION "1.0"
-+
-+#define CAPI_INTEROPERABILITY 0x20
-+
-+#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-+#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-+#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-+#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-+
-+#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
-+#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
-+
-+#define CAPI_FUNCTION_REGISTER 0
-+#define CAPI_FUNCTION_RELEASE 1
-+#define CAPI_FUNCTION_GET_PROFILE 2
-+#define CAPI_FUNCTION_GET_MANUFACTURER 3
-+#define CAPI_FUNCTION_GET_VERSION 4
-+#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
-+#define CAPI_FUNCTION_MANUFACTURER 6
-+#define CAPI_FUNCTION_LOOPBACK 7
-+
-+static struct capi_driver_interface *di;
-+
-+
-+#define CMTP_MSGNUM 1
-+#define CMTP_APPLID 2
-+#define CMTP_MAPPING 3
-+
-+static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-+{
-+ struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
-+
-+ BT_DBG("session %p application %p appl %d", session, app, appl);
-+
-+ if (!app)
-+ return NULL;
-+
-+ memset(app, 0, sizeof(*app));
-+
-+ app->state = BT_OPEN;
-+ app->appl = appl;
-+
-+ list_add_tail(&app->list, &session->applications);
-+
-+ return app;
-+}
-+
-+static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-+{
-+ BT_DBG("session %p application %p", session, app);
-+
-+ if (app) {
-+ list_del(&app->list);
-+ kfree(app);
-+ }
-+}
-+
-+static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-+{
-+ struct cmtp_application *app;
-+ struct list_head *p, *n;
-+
-+ list_for_each_safe(p, n, &session->applications) {
-+ app = list_entry(p, struct cmtp_application, list);
-+ switch (pattern) {
-+ case CMTP_MSGNUM:
-+ if (app->msgnum == value)
-+ return app;
-+ break;
-+ case CMTP_APPLID:
-+ if (app->appl == value)
-+ return app;
-+ break;
-+ case CMTP_MAPPING:
-+ if (app->mapping == value)
-+ return app;
-+ break;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static int cmtp_msgnum_get(struct cmtp_session *session)
-+{
-+ session->msgnum++;
-+
-+ if ((session->msgnum & 0xff) > 200)
-+ session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-+
-+ return session->msgnum;
-+}
-+
-+
-+static void cmtp_send_interopmsg(struct cmtp_session *session,
-+ __u8 subcmd, __u16 appl, __u16 msgnum,
-+ __u16 function, unsigned char *buf, int len)
-+{
-+ struct sk_buff *skb;
-+ unsigned char *s;
-+
-+ BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
-+
-+ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for interoperability packet");
-+ return;
-+ }
-+
-+ s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-+
-+ capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
-+ capimsg_setu16(s, 2, appl);
-+ capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
-+ capimsg_setu8 (s, 5, subcmd);
-+ capimsg_setu16(s, 6, msgnum);
-+
-+ /* Interoperability selector (Bluetooth Device Management) */
-+ capimsg_setu16(s, 8, 0x0001);
-+
-+ capimsg_setu8 (s, 10, 3 + len);
-+ capimsg_setu16(s, 11, function);
-+ capimsg_setu8 (s, 13, len);
-+
-+ if (len > 0)
-+ memcpy(s + 14, buf, len);
-+
-+ cmtp_send_capimsg(session, skb);
-+}
-+
-+static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+ struct cmtp_application *application;
-+ __u16 appl, msgnum, func, info;
-+ __u32 controller;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ switch (CAPIMSG_SUBCOMMAND(skb->data)) {
-+ case CAPI_CONF:
-+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
-+ info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-+
-+ switch (func) {
-+ case CAPI_FUNCTION_REGISTER:
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
-+ if (application) {
-+ application->state = BT_CONNECTED;
-+ application->msgnum = 0;
-+ application->mapping = CAPIMSG_APPID(skb->data);
-+ wake_up_interruptible(&session->wait);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_RELEASE:
-+ appl = CAPIMSG_APPID(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+ if (application) {
-+ application->state = BT_CLOSED;
-+ application->msgnum = 0;
-+ wake_up_interruptible(&session->wait);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_PROFILE:
-+ controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+
-+ if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
-+ session->ncontroller = controller;
-+ wake_up_interruptible(&session->wait);
-+ break;
-+ }
-+
-+ if (!info && ctrl) {
-+ memcpy(&ctrl->profile,
-+ skb->data + CAPI_MSG_BASELEN + 11,
-+ sizeof(capi_profile));
-+ session->state = BT_CONNECTED;
-+ ctrl->ready(ctrl);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_MANUFACTURER:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
-+
-+ if (!info && ctrl) {
-+ strncpy(ctrl->manu,
-+ skb->data + CAPI_MSG_BASELEN + 15,
-+ skb->data[CAPI_MSG_BASELEN + 14]);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_VERSION:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+ if (!info && ctrl) {
-+ ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
-+ ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
-+ ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
-+ ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
-+ }
-+
-+ break;
-+
-+ case CAPI_FUNCTION_GET_SERIAL_NUMBER:
-+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+ if (!info && ctrl) {
-+ memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
-+ strncpy(ctrl->serial,
-+ skb->data + CAPI_MSG_BASELEN + 17,
-+ skb->data[CAPI_MSG_BASELEN + 16]);
-+ }
-+
-+ break;
-+ }
-+
-+ break;
-+
-+ case CAPI_IND:
-+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-+
-+ if (func == CAPI_FUNCTION_LOOPBACK) {
-+ appl = CAPIMSG_APPID(skb->data);
-+ msgnum = CAPIMSG_MSGID(skb->data);
-+ cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
-+ skb->data + CAPI_MSG_BASELEN + 6,
-+ skb->data[CAPI_MSG_BASELEN + 5]);
-+ }
-+
-+ break;
-+ }
-+
-+ kfree_skb(skb);
-+}
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+ struct cmtp_application *application;
-+ __u16 cmd, appl, info;
-+ __u32 ncci, contr;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
-+ cmtp_recv_interopmsg(session, skb);
-+ return;
-+ }
-+
-+ if (session->flags & (1 << CMTP_LOOPBACK)) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
-+ appl = CAPIMSG_APPID(skb->data);
-+ contr = CAPIMSG_CONTROL(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+ if (application) {
-+ appl = application->appl;
-+ CAPIMSG_SETAPPID(skb->data, appl);
-+ } else {
-+ BT_ERR("Can't find application with id %d", appl);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ if ((contr & 0x7f) == 0x01) {
-+ contr = (contr & 0xffffff80) | session->num;
-+ CAPIMSG_SETCONTROL(skb->data, contr);
-+ }
-+
-+ if (!ctrl) {
-+ BT_ERR("Can't find controller %d for message", session->num);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ switch (cmd) {
-+ case CAPI_CONNECT_B3_CONF:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+ info = CAPIMSG_U16(skb->data, 12);
-+
-+ BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info);
-+
-+ if (info == 0)
-+ ctrl->new_ncci(ctrl, appl, ncci, 8);
-+
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+
-+ case CAPI_CONNECT_B3_IND:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+
-+ BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+ ctrl->new_ncci(ctrl, appl, ncci, 8);
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+
-+ case CAPI_DISCONNECT_B3_IND:
-+ ncci = CAPIMSG_NCCI(skb->data);
-+
-+ BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+ if (ncci == 0xffffffff)
-+ BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff");
-+
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ ctrl->free_ncci(ctrl, appl, ncci);
-+ break;
-+
-+ default:
-+ ctrl->handle_capimsg(ctrl, appl, skb);
-+ break;
-+ }
-+}
-+
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ struct cmtp_scb *scb = (void *) skb->cb;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ scb->id = -1;
-+ scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-+
-+ skb_queue_tail(&session->transmit, skb);
-+
-+ cmtp_schedule(session);
-+}
-+
-+
-+static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-+{
-+ BT_DBG("ctrl %p data %p", ctrl, data);
-+
-+ return -EIO;
-+}
-+
-+static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-+{
-+ BT_DBG("ctrl %p", ctrl);
-+
-+ ctrl->reseted(ctrl);
-+}
-+
-+static void cmtp_remove_ctr(struct capi_ctr *ctrl)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+
-+ BT_DBG("ctrl %p", ctrl);
-+
-+ ctrl->suspend_output(ctrl);
-+
-+ atomic_inc(&session->terminate);
-+ cmtp_schedule(session);
-+}
-+
-+static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+ unsigned char buf[8];
-+ int err = 0, nconn, want = rp->level3cnt;
-+
-+ BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
-+ ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-+
-+ application = cmtp_application_add(session, appl);
-+ if (!application) {
-+ BT_ERR("Can't allocate memory for new application");
-+ ctrl->appl_released(ctrl, appl);
-+ return;
-+ }
-+
-+ if (want < 0)
-+ nconn = ctrl->profile.nbchannel * -want;
-+ else
-+ nconn = want;
-+
-+ if (nconn == 0)
-+ nconn = ctrl->profile.nbchannel;
-+
-+ capimsg_setu16(buf, 0, nconn);
-+ capimsg_setu16(buf, 2, rp->datablkcnt);
-+ capimsg_setu16(buf, 4, rp->datablklen);
-+
-+ application->state = BT_CONFIG;
-+ application->msgnum = cmtp_msgnum_get(session);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
-+ CAPI_FUNCTION_REGISTER, buf, 6);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (1) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ if (application->state == BT_CLOSED) {
-+ err = -application->err;
-+ break;
-+ }
-+
-+ if (application->state == BT_CONNECTED)
-+ break;
-+
-+ if (signal_pending(current)) {
-+ err = -EINTR;
-+ break;
-+ }
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ if (err) {
-+ ctrl->appl_released(ctrl, appl);
-+ cmtp_application_del(session, application);
-+ return;
-+ }
-+
-+ ctrl->appl_registered(ctrl, appl);
-+}
-+
-+static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+
-+ BT_DBG("ctrl %p appl %d", ctrl, appl);
-+
-+ application = cmtp_application_get(session, CMTP_APPLID, appl);
-+ if (!application) {
-+ BT_ERR("Can't find application");
-+ return;
-+ }
-+
-+ application->msgnum = cmtp_msgnum_get(session);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
-+ CAPI_FUNCTION_RELEASE, NULL, 0);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (timeo) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (application->state == BT_CLOSED)
-+ break;
-+
-+ if (signal_pending(current))
-+ break;
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ cmtp_application_del(session, application);
-+ ctrl->appl_released(ctrl, appl);
-+}
-+
-+static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *application;
-+ __u16 appl;
-+ __u32 contr;
-+
-+ BT_DBG("ctrl %p skb %p", ctrl, skb);
-+
-+ appl = CAPIMSG_APPID(skb->data);
-+ contr = CAPIMSG_CONTROL(skb->data);
-+
-+ application = cmtp_application_get(session, CMTP_APPLID, appl);
-+ if ((!application) || (application->state != BT_CONNECTED)) {
-+ BT_ERR("Can't find application with id %d", appl);
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ CAPIMSG_SETAPPID(skb->data, application->mapping);
-+
-+ if ((contr & 0x7f) == session->num) {
-+ contr = (contr & 0xffffff80) | 0x01;
-+ CAPIMSG_SETCONTROL(skb->data, contr);
-+ }
-+
-+ cmtp_send_capimsg(session, skb);
-+}
-+
-+static char *cmtp_procinfo(struct capi_ctr *ctrl)
-+{
-+ return "CAPI Message Transport Protocol";
-+}
-+
-+static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
-+{
-+ struct cmtp_session *session = ctrl->driverdata;
-+ struct cmtp_application *app;
-+ struct list_head *p, *n;
-+ int len = 0;
-+
-+ len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION);
-+ len += sprintf(page + len, "addr %s\n", session->name);
-+ len += sprintf(page + len, "ctrl %d\n", session->num);
-+
-+ list_for_each_safe(p, n, &session->applications) {
-+ app = list_entry(p, struct cmtp_application, list);
-+ len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
-+ }
-+
-+ if (off + count >= len)
-+ *eof = 1;
-+
-+ if (len < off)
-+ return 0;
-+
-+ *start = page + off;
-+
-+ return ((count < len - off) ? count : len - off);
-+}
-+
-+static struct capi_driver cmtp_driver = {
-+ name: "cmtp",
-+ revision: REVISION,
-+ load_firmware: cmtp_load_firmware,
-+ reset_ctr: cmtp_reset_ctr,
-+ remove_ctr: cmtp_remove_ctr,
-+ register_appl: cmtp_register_appl,
-+ release_appl: cmtp_release_appl,
-+ send_message: cmtp_send_message,
-+ procinfo: cmtp_procinfo,
-+ ctr_read_proc: cmtp_ctr_read_proc,
-+
-+ driver_read_proc: 0,
-+ add_card: 0,
-+};
-+
-+
-+int cmtp_attach_device(struct cmtp_session *session)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+ unsigned char buf[4];
-+
-+ BT_DBG("session %p", session);
-+
-+ capimsg_setu32(buf, 0, 0);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
-+ CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+ add_wait_queue(&session->wait, &wait);
-+ while (timeo) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (session->ncontroller)
-+ break;
-+
-+ if (signal_pending(current))
-+ break;
-+
-+ timeo = schedule_timeout(timeo);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&session->wait, &wait);
-+
-+ BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-+
-+ if (!timeo)
-+ return -ETIMEDOUT;
-+
-+ if (!session->ncontroller)
-+ return -ENODEV;
-+
-+
-+ if (session->ncontroller > 1)
-+ BT_INFO("Setting up only CAPI controller 1");
-+
-+ if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) {
-+ BT_ERR("Can't attach new controller");
-+ return -EBUSY;
-+ }
-+
-+ session->num = session->ctrl->cnr;
-+
-+ BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num);
-+
-+ capimsg_setu32(buf, 0, 1);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_VERSION, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-+
-+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+ CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+ return 0;
-+}
-+
-+void cmtp_detach_device(struct cmtp_session *session)
-+{
-+ struct capi_ctr *ctrl = session->ctrl;
-+
-+ BT_DBG("session %p ctrl %p", session, ctrl);
-+
-+ if (!ctrl)
-+ return;
-+
-+ ctrl->reseted(ctrl);
-+
-+ di->detach_ctr(ctrl);
-+}
-+
-+int cmtp_init_capi(void)
-+{
-+ if (!(di = attach_capi_driver(&cmtp_driver))) {
-+ BT_ERR("Can't attach CAPI driver");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+void cmtp_cleanup_capi(void)
-+{
-+ detach_capi_driver(&cmtp_driver);
-+}
-diff -urN linux-2.4.18/net/bluetooth/cmtp/cmtp.h linux-2.4.18-mh9/net/bluetooth/cmtp/cmtp.h
---- linux-2.4.18/net/bluetooth/cmtp/cmtp.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/cmtp/cmtp.h Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,138 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#ifndef __CMTP_H
-+#define __CMTP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+#define BTNAMSIZ 18
-+
-+/* CMTP ioctl defines */
-+#define CMTPCONNADD _IOW('C', 200, int)
-+#define CMTPCONNDEL _IOW('C', 201, int)
-+#define CMTPGETCONNLIST _IOR('C', 210, int)
-+#define CMTPGETCONNINFO _IOR('C', 211, int)
-+
-+#define CMTP_LOOPBACK 0
-+
-+struct cmtp_connadd_req {
-+ int sock; // Connected socket
-+ __u32 flags;
-+};
-+
-+struct cmtp_conndel_req {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+};
-+
-+struct cmtp_conninfo {
-+ bdaddr_t bdaddr;
-+ __u32 flags;
-+ __u16 state;
-+ int num;
-+};
-+
-+struct cmtp_connlist_req {
-+ __u32 cnum;
-+ struct cmtp_conninfo *ci;
-+};
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
-+int cmtp_del_connection(struct cmtp_conndel_req *req);
-+int cmtp_get_connlist(struct cmtp_connlist_req *req);
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci);
-+
-+/* CMTP session defines */
-+#define CMTP_INTEROP_TIMEOUT (HZ * 5)
-+#define CMTP_INITIAL_MSGNUM 0xff00
-+
-+struct cmtp_session {
-+ struct list_head list;
-+
-+ struct socket *sock;
-+
-+ bdaddr_t bdaddr;
-+
-+ unsigned long state;
-+ unsigned long flags;
-+
-+ uint mtu;
-+
-+ char name[BTNAMSIZ];
-+
-+ atomic_t terminate;
-+
-+ wait_queue_head_t wait;
-+
-+ int ncontroller;
-+ int num;
-+ struct capi_ctr *ctrl;
-+
-+ struct list_head applications;
-+
-+ unsigned long blockids;
-+ int msgnum;
-+
-+ struct sk_buff_head transmit;
-+
-+ struct sk_buff *reassembly[16];
-+};
-+
-+struct cmtp_application {
-+ struct list_head list;
-+
-+ unsigned long state;
-+ int err;
-+
-+ __u16 appl;
-+ __u16 mapping;
-+
-+ __u16 msgnum;
-+};
-+
-+struct cmtp_scb {
-+ int id;
-+ int data;
-+};
-+
-+int cmtp_attach_device(struct cmtp_session *session);
-+void cmtp_detach_device(struct cmtp_session *session);
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-+
-+static inline void cmtp_schedule(struct cmtp_session *session)
-+{
-+ struct sock *sk = session->sock->sk;
-+
-+ wake_up_interruptible(sk->sleep);
-+}
-+
-+/* CMTP init defines */
-+int cmtp_init_capi(void);
-+int cmtp_init_sockets(void);
-+void cmtp_cleanup_capi(void);
-+void cmtp_cleanup_sockets(void);
-+
-+#endif /* __CMTP_H */
-diff -urN linux-2.4.18/net/bluetooth/cmtp/core.c linux-2.4.18-mh9/net/bluetooth/cmtp/core.c
---- linux-2.4.18/net/bluetooth/cmtp/core.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/cmtp/core.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,515 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <linux/init.h>
-+#include <net/sock.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.0"
-+
-+static DECLARE_RWSEM(cmtp_session_sem);
-+static LIST_HEAD(cmtp_session_list);
-+
-+static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-+{
-+ struct cmtp_session *session;
-+ struct list_head *p;
-+
-+ BT_DBG("");
-+
-+ list_for_each(p, &cmtp_session_list) {
-+ session = list_entry(p, struct cmtp_session, list);
-+ if (!bacmp(bdaddr, &session->bdaddr))
-+ return session;
-+ }
-+ return NULL;
-+}
-+
-+static void __cmtp_link_session(struct cmtp_session *session)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add(&session->list, &cmtp_session_list);
-+}
-+
-+static void __cmtp_unlink_session(struct cmtp_session *session)
-+{
-+ list_del(&session->list);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-+{
-+ bacpy(&ci->bdaddr, &session->bdaddr);
-+
-+ ci->flags = session->flags;
-+ ci->state = session->state;
-+
-+ ci->num = session->num;
-+}
-+
-+
-+static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-+{
-+ int i, id = -1;
-+
-+ for (i = 0; i < 16; i++)
-+ if (!test_and_set_bit(i, &session->blockids)) {
-+ id = i;
-+ break;
-+ }
-+
-+ return id;
-+}
-+
-+static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-+{
-+ clear_bit(id, &session->blockids);
-+}
-+
-+static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-+{
-+ struct sk_buff *skb = session->reassembly[id], *nskb;
-+ int size;
-+
-+ BT_DBG("session %p buf %p count %d", session, buf, count);
-+
-+ size = (skb) ? skb->len + count : count;
-+
-+ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for CAPI message");
-+ return;
-+ }
-+
-+ if (skb && (skb->len > 0))
-+ memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
-+
-+ memcpy(skb_put(nskb, count), buf, count);
-+
-+ session->reassembly[id] = nskb;
-+
-+ if (skb)
-+ kfree_skb(skb);
-+}
-+
-+static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+ __u8 hdr, hdrlen, id;
-+ __u16 len;
-+
-+ BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+ while (skb->len > 0) {
-+ hdr = skb->data[0];
-+
-+ switch (hdr & 0xc0) {
-+ case 0x40:
-+ hdrlen = 2;
-+ len = skb->data[1];
-+ break;
-+ case 0x80:
-+ hdrlen = 3;
-+ len = skb->data[1] | (skb->data[2] << 8);
-+ break;
-+ default:
-+ hdrlen = 1;
-+ len = 0;
-+ break;
-+ }
-+
-+ id = (hdr & 0x3c) >> 2;
-+
-+ BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-+
-+ if (hdrlen + len > skb->len) {
-+ BT_ERR("Wrong size or header information in CMTP frame");
-+ break;
-+ }
-+
-+ if (len == 0) {
-+ skb_pull(skb, hdrlen);
-+ continue;
-+ }
-+
-+ switch (hdr & 0x03) {
-+ case 0x00:
-+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+ cmtp_recv_capimsg(session, session->reassembly[id]);
-+ session->reassembly[id] = NULL;
-+ break;
-+ case 0x01:
-+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+ break;
-+ default:
-+ if (session->reassembly[id] != NULL)
-+ kfree_skb(session->reassembly[id]);
-+ session->reassembly[id] = NULL;
-+ break;
-+ }
-+
-+ skb_pull(skb, hdrlen + len);
-+ }
-+
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-+{
-+ struct socket *sock = session->sock;
-+ struct iovec iv = { data, len };
-+ struct msghdr msg;
-+ int err;
-+
-+ BT_DBG("session %p data %p len %d", session, data, len);
-+
-+ if (!len)
-+ return 0;
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ err = sock->ops->sendmsg(sock, &msg, len, 0);
-+ return err;
-+}
-+
-+static int cmtp_process_transmit(struct cmtp_session *session)
-+{
-+ struct sk_buff *skb, *nskb;
-+ unsigned char *hdr;
-+ unsigned int size, tail;
-+
-+ BT_DBG("session %p", session);
-+
-+ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
-+ BT_ERR("Can't allocate memory for new frame");
-+ return -ENOMEM;
-+ }
-+
-+ while ((skb = skb_dequeue(&session->transmit))) {
-+ struct cmtp_scb *scb = (void *) skb->cb;
-+
-+ if ((tail = (session->mtu - nskb->len)) < 5) {
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+ skb_trim(nskb, 0);
-+ tail = session->mtu;
-+ }
-+
-+ size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-+
-+ if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
-+ skb_queue_head(&session->transmit, skb);
-+ break;
-+ }
-+
-+ if (size < 256) {
-+ hdr = skb_put(nskb, 2);
-+ hdr[0] = 0x40
-+ | ((scb->id << 2) & 0x3c)
-+ | ((skb->len == size) ? 0x00 : 0x01);
-+ hdr[1] = size;
-+ } else {
-+ hdr = skb_put(nskb, 3);
-+ hdr[0] = 0x80
-+ | ((scb->id << 2) & 0x3c)
-+ | ((skb->len == size) ? 0x00 : 0x01);
-+ hdr[1] = size & 0xff;
-+ hdr[2] = size >> 8;
-+ }
-+
-+ memcpy(skb_put(nskb, size), skb->data, size);
-+ skb_pull(skb, size);
-+
-+ if (skb->len > 0) {
-+ skb_queue_head(&session->transmit, skb);
-+ } else {
-+ cmtp_free_block_id(session, scb->id);
-+ if (scb->data) {
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+ skb_trim(nskb, 0);
-+ }
-+ kfree_skb(skb);
-+ }
-+ }
-+
-+ cmtp_send_frame(session, nskb->data, nskb->len);
-+
-+ kfree_skb(nskb);
-+
-+ return skb_queue_len(&session->transmit);
-+}
-+
-+static int cmtp_session(void *arg)
-+{
-+ struct cmtp_session *session = arg;
-+ struct sock *sk = session->sock->sk;
-+ struct sk_buff *skb;
-+ wait_queue_t wait;
-+
-+ BT_DBG("session %p", session);
-+
-+ daemonize(); reparent_to_init();
-+
-+ sprintf(current->comm, "kcmtpd_ctr_%d", session->num);
-+
-+ sigfillset(&current->blocked);
-+ flush_signals(current);
-+
-+ current->nice = -15;
-+
-+ set_fs(KERNEL_DS);
-+
-+ init_waitqueue_entry(&wait, current);
-+ add_wait_queue(sk->sleep, &wait);
-+ while (!atomic_read(&session->terminate)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (sk->state != BT_CONNECTED)
-+ break;
-+
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ cmtp_recv_frame(session, skb);
-+ }
-+
-+ cmtp_process_transmit(session);
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ down_write(&cmtp_session_sem);
-+
-+ if (!(session->flags & (1 << CMTP_LOOPBACK)))
-+ cmtp_detach_device(session);
-+
-+ fput(session->sock->file);
-+
-+ __cmtp_unlink_session(session);
-+
-+ up_write(&cmtp_session_sem);
-+
-+ kfree(session);
-+ return 0;
-+}
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-+{
-+ struct cmtp_session *session, *s;
-+ bdaddr_t src, dst;
-+ int i, err;
-+
-+ BT_DBG("");
-+
-+ baswap(&src, &bluez_pi(sock->sk)->src);
-+ baswap(&dst, &bluez_pi(sock->sk)->dst);
-+
-+ session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
-+ if (!session)
-+ return -ENOMEM;
-+ memset(session, 0, sizeof(struct cmtp_session));
-+
-+ down_write(&cmtp_session_sem);
-+
-+ s = __cmtp_get_session(&bluez_pi(sock->sk)->dst);
-+ if (s && s->state == BT_CONNECTED) {
-+ err = -EEXIST;
-+ goto failed;
-+ }
-+
-+ bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst);
-+
-+ session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
-+
-+ BT_DBG("mtu %d", session->mtu);
-+
-+ sprintf(session->name, "%s", batostr(&dst));
-+
-+ session->sock = sock;
-+ session->state = BT_CONFIG;
-+
-+ init_waitqueue_head(&session->wait);
-+
-+ session->ctrl = NULL;
-+ session->msgnum = CMTP_INITIAL_MSGNUM;
-+
-+ INIT_LIST_HEAD(&session->applications);
-+
-+ skb_queue_head_init(&session->transmit);
-+
-+ for (i = 0; i < 16; i++)
-+ session->reassembly[i] = NULL;
-+
-+ session->flags = req->flags;
-+
-+ __cmtp_link_session(session);
-+
-+ err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (err < 0)
-+ goto unlink;
-+
-+ if (!(session->flags & (1 << CMTP_LOOPBACK))) {
-+ err = cmtp_attach_device(session);
-+ if (err < 0)
-+ goto detach;
-+ }
-+
-+ up_write(&cmtp_session_sem);
-+ return 0;
-+
-+detach:
-+ cmtp_detach_device(session);
-+
-+unlink:
-+ __cmtp_unlink_session(session);
-+
-+failed:
-+ up_write(&cmtp_session_sem);
-+ kfree(session);
-+ return err;
-+}
-+
-+int cmtp_del_connection(struct cmtp_conndel_req *req)
-+{
-+ struct cmtp_session *session;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&cmtp_session_sem);
-+
-+ session = __cmtp_get_session(&req->bdaddr);
-+ if (session) {
-+ /* Flush the transmit queue */
-+ skb_queue_purge(&session->transmit);
-+
-+ /* Kill session thread */
-+ atomic_inc(&session->terminate);
-+ cmtp_schedule(session);
-+ } else
-+ err = -ENOENT;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+int cmtp_get_connlist(struct cmtp_connlist_req *req)
-+{
-+ struct list_head *p;
-+ int err = 0, n = 0;
-+
-+ BT_DBG("");
-+
-+ down_read(&cmtp_session_sem);
-+
-+ list_for_each(p, &cmtp_session_list) {
-+ struct cmtp_session *session;
-+ struct cmtp_conninfo ci;
-+
-+ session = list_entry(p, struct cmtp_session, list);
-+
-+ __cmtp_copy_session(session, &ci);
-+
-+ if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (++n >= req->cnum)
-+ break;
-+
-+ req->ci++;
-+ }
-+ req->cnum = n;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-+{
-+ struct cmtp_session *session;
-+ int err = 0;
-+
-+ down_read(&cmtp_session_sem);
-+
-+ session = __cmtp_get_session(&ci->bdaddr);
-+ if (session)
-+ __cmtp_copy_session(session, ci);
-+ else
-+ err = -ENOENT;
-+
-+ up_read(&cmtp_session_sem);
-+ return err;
-+}
-+
-+
-+int __init init_cmtp(void)
-+{
-+ l2cap_load();
-+
-+ cmtp_init_capi();
-+ cmtp_init_sockets();
-+
-+ BT_INFO("BlueZ CMTP ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+ return 0;
-+}
-+
-+void __exit exit_cmtp(void)
-+{
-+ cmtp_cleanup_sockets();
-+ cmtp_cleanup_capi();
-+}
-+
-+module_init(init_cmtp);
-+module_exit(exit_cmtp);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/cmtp/sock.c linux-2.4.18-mh9/net/bluetooth/cmtp/sock.c
---- linux-2.4.18/net/bluetooth/cmtp/sock.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/cmtp/sock.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,236 @@
-+/*
-+ CMTP implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/ioctl.h>
-+#include <linux/file.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static inline struct socket *socki_lookup(struct inode *inode)
-+{
-+ return &inode->u.socket_i;
-+}
-+
-+static struct socket *sockfd_lookup(int fd, int *err)
-+{
-+ struct file *file;
-+ struct inode *inode;
-+ struct socket *sock;
-+
-+ if (!(file = fget(fd))) {
-+ *err = -EBADF;
-+ return NULL;
-+ }
-+
-+ inode = file->f_dentry->d_inode;
-+ if (!inode->i_sock || !(sock = socki_lookup(inode))) {
-+ *err = -ENOTSOCK;
-+ fput(file);
-+ return NULL;
-+ }
-+
-+ if (sock->file != file) {
-+ printk(KERN_ERR "socki_lookup: socket file changed!\n");
-+ sock->file = file;
-+ }
-+ return sock;
-+}
-+
-+static int cmtp_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sock_orphan(sk);
-+ sock_put(sk);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct cmtp_connadd_req ca;
-+ struct cmtp_conndel_req cd;
-+ struct cmtp_connlist_req cl;
-+ struct cmtp_conninfo ci;
-+ struct socket *nsock;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
-+ case CMTPCONNADD:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
-+ return -EFAULT;
-+
-+ nsock = sockfd_lookup(ca.sock, &err);
-+ if (!nsock)
-+ return err;
-+
-+ if (nsock->sk->state != BT_CONNECTED)
-+ return -EBADFD;
-+
-+ err = cmtp_add_connection(&ca, nsock);
-+ if (!err) {
-+ if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+ err = -EFAULT;
-+ } else
-+ fput(nsock->file);
-+
-+ return err;
-+
-+ case CMTPCONNDEL:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-+
-+ if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+ return -EFAULT;
-+
-+ return cmtp_del_connection(&cd);
-+
-+ case CMTPGETCONNLIST:
-+ if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+ return -EFAULT;
-+
-+ if (cl.cnum <= 0)
-+ return -EINVAL;
-+
-+ err = cmtp_get_connlist(&cl);
-+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+ return -EFAULT;
-+
-+ return err;
-+
-+ case CMTPGETCONNINFO:
-+ if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+ return -EFAULT;
-+
-+ err = cmtp_get_conninfo(&ci);
-+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+ return -EFAULT;
-+
-+ return err;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static struct proto_ops cmtp_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: cmtp_sock_release,
-+ ioctl: cmtp_sock_ioctl,
-+ bind: sock_no_bind,
-+ getname: sock_no_getname,
-+ sendmsg: sock_no_sendmsg,
-+ recvmsg: sock_no_recvmsg,
-+ poll: sock_no_poll,
-+ listen: sock_no_listen,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ mmap: sock_no_mmap
-+};
-+
-+static int cmtp_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ if (sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &cmtp_sock_ops;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+ return -ENOMEM;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ sock->state = SS_UNCONNECTED;
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->protocol = protocol;
-+
-+ return 0;
-+}
-+
-+static struct net_proto_family cmtp_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: cmtp_sock_create
-+};
-+
-+int cmtp_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
-+ BT_ERR("Can't register CMTP socket layer (%d)", err);
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+void cmtp_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
-+ BT_ERR("Can't unregister CMTP socket layer (%d)", err);
-+
-+ return;
-+}
-diff -urN linux-2.4.18/net/bluetooth/hci_conn.c linux-2.4.18-mh9/net/bluetooth/hci_conn.c
---- linux-2.4.18/net/bluetooth/hci_conn.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/hci_conn.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,441 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * HCI Connection handling.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/notifier.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef HCI_CORE_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+void hci_acl_connect(struct hci_conn *conn)
-+{
-+ struct hci_dev *hdev = conn->hdev;
-+ struct inquiry_entry *ie;
-+ create_conn_cp cp;
-+
-+ BT_DBG("%p", conn);
-+
-+ conn->state = BT_CONNECT;
-+ conn->out = 1;
-+ conn->link_mode = HCI_LM_MASTER;
-+
-+ memset(&cp, 0, sizeof(cp));
-+ bacpy(&cp.bdaddr, &conn->dst);
-+ cp.pscan_rep_mode = 0x01;
-+
-+ if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
-+ inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
-+ cp.pscan_rep_mode = ie->info.pscan_rep_mode;
-+ cp.pscan_mode = ie->info.pscan_mode;
-+ cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000);
-+ }
-+
-+ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
-+ if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
-+ cp.role_switch = 0x01;
-+ else
-+ cp.role_switch = 0x00;
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
-+ CREATE_CONN_CP_SIZE, &cp);
-+}
-+
-+void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
-+{
-+ disconnect_cp cp;
-+
-+ BT_DBG("%p", conn);
-+
-+ conn->state = BT_DISCONN;
-+
-+ cp.handle = __cpu_to_le16(conn->handle);
-+ cp.reason = reason;
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
-+ DISCONNECT_CP_SIZE, &cp);
-+}
-+
-+void hci_add_sco(struct hci_conn *conn, __u16 handle)
-+{
-+ struct hci_dev *hdev = conn->hdev;
-+ add_sco_cp cp;
-+
-+ BT_DBG("%p", conn);
-+
-+ conn->state = BT_CONNECT;
-+ conn->out = 1;
-+
-+ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-+ cp.handle = __cpu_to_le16(handle);
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
-+}
-+
-+static void hci_conn_timeout(unsigned long arg)
-+{
-+ struct hci_conn *conn = (void *)arg;
-+ struct hci_dev *hdev = conn->hdev;
-+
-+ BT_DBG("conn %p state %d", conn, conn->state);
-+
-+ if (atomic_read(&conn->refcnt))
-+ return;
-+
-+ hci_dev_lock(hdev);
-+ if (conn->state == BT_CONNECTED)
-+ hci_acl_disconn(conn, 0x13);
-+ else
-+ conn->state = BT_CLOSED;
-+ hci_dev_unlock(hdev);
-+ return;
-+}
-+
-+static void hci_conn_init_timer(struct hci_conn *conn)
-+{
-+ init_timer(&conn->timer);
-+ conn->timer.function = hci_conn_timeout;
-+ conn->timer.data = (unsigned long)conn;
-+}
-+
-+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
-+{
-+ struct hci_conn *conn;
-+
-+ BT_DBG("%s dst %s", hdev->name, batostr(dst));
-+
-+ if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
-+ return NULL;
-+ memset(conn, 0, sizeof(struct hci_conn));
-+
-+ bacpy(&conn->dst, dst);
-+ conn->type = type;
-+ conn->hdev = hdev;
-+ conn->state = BT_OPEN;
-+
-+ skb_queue_head_init(&conn->data_q);
-+ hci_conn_init_timer(conn);
-+
-+ atomic_set(&conn->refcnt, 0);
-+
-+ hci_dev_hold(hdev);
-+
-+ if (hdev->notify)
-+ hdev->notify(hdev, HCI_NOTIFY_CONN_ADD, (unsigned long) conn);
-+
-+ tasklet_disable(&hdev->tx_task);
-+ conn_hash_add(hdev, conn);
-+ tasklet_enable(&hdev->tx_task);
-+
-+ return conn;
-+}
-+
-+int hci_conn_del(struct hci_conn *conn)
-+{
-+ struct hci_dev *hdev = conn->hdev;
-+
-+ BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
-+
-+ hci_conn_del_timer(conn);
-+
-+ if (conn->type == SCO_LINK) {
-+ struct hci_conn *acl = conn->link;
-+ if (acl) {
-+ acl->link = NULL;
-+ hci_conn_put(acl);
-+ }
-+ } else {
-+ struct hci_conn *sco = conn->link;
-+ if (sco)
-+ sco->link = NULL;
-+
-+ /* Unacked frames */
-+ hdev->acl_cnt += conn->sent;
-+ }
-+
-+ tasklet_disable(&hdev->tx_task);
-+ conn_hash_del(hdev, conn);
-+ tasklet_enable(&hdev->tx_task);
-+
-+ skb_queue_purge(&conn->data_q);
-+
-+ if (hdev->notify)
-+ hdev->notify(hdev, HCI_NOTIFY_CONN_DEL, (unsigned long) conn);
-+
-+ hci_dev_put(hdev);
-+
-+ kfree(conn);
-+ return 0;
-+}
-+
-+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
-+{
-+ int use_src = bacmp(src, BDADDR_ANY);
-+ struct hci_dev *hdev = NULL;
-+ struct list_head *p;
-+
-+ BT_DBG("%s -> %s", batostr(src), batostr(dst));
-+
-+ read_lock_bh(&hdev_list_lock);
-+
-+ list_for_each(p, &hdev_list) {
-+ struct hci_dev *d;
-+ d = list_entry(p, struct hci_dev, list);
-+
-+ if (!test_bit(HCI_UP, &d->flags))
-+ continue;
-+
-+ /* Simple routing:
-+ * No source address - find interface with bdaddr != dst
-+ * Source address - find interface with bdaddr == src
-+ */
-+
-+ if (use_src) {
-+ if (!bacmp(&d->bdaddr, src)) {
-+ hdev = d; break;
-+ }
-+ } else {
-+ if (bacmp(&d->bdaddr, dst)) {
-+ hdev = d; break;
-+ }
-+ }
-+ }
-+
-+ if (hdev)
-+ hci_dev_hold(hdev);
-+
-+ read_unlock_bh(&hdev_list_lock);
-+ return hdev;
-+}
-+
-+/* Create SCO or ACL connection.
-+ * Device _must_ be locked */
-+struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
-+{
-+ struct hci_conn *acl;
-+
-+ BT_DBG("%s dst %s", hdev->name, batostr(dst));
-+
-+ if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
-+ if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
-+ return NULL;
-+ }
-+
-+ hci_conn_hold(acl);
-+
-+ if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
-+ hci_acl_connect(acl);
-+
-+ if (type == SCO_LINK) {
-+ struct hci_conn *sco;
-+
-+ if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
-+ if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
-+ hci_conn_put(acl);
-+ return NULL;
-+ }
-+ }
-+ acl->link = sco;
-+ sco->link = acl;
-+
-+ hci_conn_hold(sco);
-+
-+ if (acl->state == BT_CONNECTED &&
-+ (sco->state == BT_OPEN || sco->state == BT_CLOSED))
-+ hci_add_sco(sco, acl->handle);
-+
-+ return sco;
-+ } else {
-+ return acl;
-+ }
-+}
-+
-+/* Authenticate remote device */
-+int hci_conn_auth(struct hci_conn *conn)
-+{
-+ BT_DBG("conn %p", conn);
-+
-+ if (conn->link_mode & HCI_LM_AUTH)
-+ return 1;
-+
-+ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
-+ auth_requested_cp ar;
-+ ar.handle = __cpu_to_le16(conn->handle);
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-+ AUTH_REQUESTED_CP_SIZE, &ar);
-+ }
-+ return 0;
-+}
-+
-+/* Enable encryption */
-+int hci_conn_encrypt(struct hci_conn *conn)
-+{
-+ BT_DBG("conn %p", conn);
-+
-+ if (conn->link_mode & HCI_LM_ENCRYPT)
-+ return 1;
-+
-+ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
-+ return 0;
-+
-+ if (hci_conn_auth(conn)) {
-+ set_conn_encrypt_cp ce;
-+ ce.handle = __cpu_to_le16(conn->handle);
-+ ce.encrypt = 1;
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
-+ SET_CONN_ENCRYPT_CP_SIZE, &ce);
-+ }
-+ return 0;
-+}
-+
-+/* Drop all connection on the device */
-+void hci_conn_hash_flush(struct hci_dev *hdev)
-+{
-+ struct conn_hash *h = &hdev->conn_hash;
-+ struct list_head *p;
-+
-+ BT_DBG("hdev %s", hdev->name);
-+
-+ p = h->list.next;
-+ while (p != &h->list) {
-+ struct hci_conn *c;
-+
-+ c = list_entry(p, struct hci_conn, list);
-+ p = p->next;
-+
-+ c->state = BT_CLOSED;
-+
-+ hci_proto_disconn_ind(c, 0x16);
-+ hci_conn_del(c);
-+ }
-+}
-+
-+int hci_get_conn_list(unsigned long arg)
-+{
-+ struct hci_conn_list_req req, *cl;
-+ struct hci_conn_info *ci;
-+ struct hci_dev *hdev;
-+ struct list_head *p;
-+ int n = 0, size;
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ if (!(hdev = hci_dev_get(req.dev_id)))
-+ return -ENODEV;
-+
-+ size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
-+
-+ if (verify_area(VERIFY_WRITE, (void *)arg, size))
-+ return -EFAULT;
-+
-+ if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
-+ return -ENOMEM;
-+ ci = cl->conn_info;
-+
-+ hci_dev_lock_bh(hdev);
-+ list_for_each(p, &hdev->conn_hash.list) {
-+ register struct hci_conn *c;
-+ c = list_entry(p, struct hci_conn, list);
-+
-+ bacpy(&(ci + n)->bdaddr, &c->dst);
-+ (ci + n)->handle = c->handle;
-+ (ci + n)->type = c->type;
-+ (ci + n)->out = c->out;
-+ (ci + n)->state = c->state;
-+ (ci + n)->link_mode = c->link_mode;
-+ n++;
-+ }
-+ hci_dev_unlock_bh(hdev);
-+
-+ cl->dev_id = hdev->id;
-+ cl->conn_num = n;
-+ size = n * sizeof(struct hci_conn_info) + sizeof(req);
-+
-+ hci_dev_put(hdev);
-+
-+ copy_to_user((void *) arg, cl, size);
-+ kfree(cl);
-+
-+ return 0;
-+}
-+
-+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
-+{
-+ struct hci_conn_info_req req;
-+ struct hci_conn_info ci;
-+ struct hci_conn *conn;
-+ char *ptr = (void *) arg + sizeof(req);
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
-+ return -EFAULT;
-+
-+ hci_dev_lock_bh(hdev);
-+ conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
-+ if (conn) {
-+ bacpy(&ci.bdaddr, &conn->dst);
-+ ci.handle = conn->handle;
-+ ci.type = conn->type;
-+ ci.out = conn->out;
-+ ci.state = conn->state;
-+ ci.link_mode = conn->link_mode;
-+ }
-+ hci_dev_unlock_bh(hdev);
-+
-+ if (!conn)
-+ return -ENOENT;
-+
-+ copy_to_user(ptr, &ci, sizeof(ci));
-+ return 0;
-+}
-diff -urN linux-2.4.18/net/bluetooth/hci_core.c linux-2.4.18-mh9/net/bluetooth/hci_core.c
---- linux-2.4.18/net/bluetooth/hci_core.c Fri Nov 9 23:21:21 2001
-+++ linux-2.4.18-mh9/net/bluetooth/hci_core.c Mon Aug 25 18:38:12 2003
-@@ -25,11 +25,12 @@
- /*
- * BlueZ HCI Core.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
-+#include <linux/kmod.h>
-
- #include <linux/types.h>
- #include <linux/errno.h>
-@@ -50,12 +51,11 @@
- #include <asm/unaligned.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
-
- #ifndef HCI_CORE_DEBUG
--#undef DBG
--#define DBG( A... )
-+#undef BT_DBG
-+#define BT_DBG( A... )
- #endif
-
- static void hci_cmd_task(unsigned long arg);
-@@ -63,279 +63,69 @@
- static void hci_tx_task(unsigned long arg);
- static void hci_notify(struct hci_dev *hdev, int event);
-
--static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
-+rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
-
- /* HCI device list */
--struct hci_dev *hdev_list[HCI_MAX_DEV];
--spinlock_t hdev_list_lock;
--#define GET_HDEV(a) (hdev_list[a])
--
--/* HCI protocol list */
--struct hci_proto *hproto_list[HCI_MAX_PROTO];
--#define GET_HPROTO(a) (hproto_list[a])
-+LIST_HEAD(hdev_list);
-+rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
-
--/* HCI notifiers list */
--struct notifier_block *hci_dev_notifier;
--
--/* HCI device notifications */
--int hci_register_notifier(struct notifier_block *nb)
--{
-- int err, i;
-- struct hci_dev *hdev;
--
-- if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
-- return err;
--
-- /* Notify about already registered devices */
-- spin_lock(&hdev_list_lock);
-- for (i = 0; i < HCI_MAX_DEV; i++) {
-- if (!(hdev = GET_HDEV(i)))
-- continue;
-- if (hdev->flags & HCI_UP)
-- (*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
-- }
-- spin_unlock(&hdev_list_lock);
--
-- return 0;
--}
--
--int hci_unregister_notifier(struct notifier_block *nb)
--{
-- return notifier_chain_unregister(&hci_dev_notifier, nb);
--}
--
--static inline void hci_notify(struct hci_dev *hdev, int event)
--{
-- notifier_call_chain(&hci_dev_notifier, event, hdev);
--}
--
--/* Get HCI device by index (device is locked on return)*/
--struct hci_dev *hci_dev_get(int index)
--{
-- struct hci_dev *hdev;
-- DBG("%d", index);
--
-- if (index < 0 || index >= HCI_MAX_DEV)
-- return NULL;
--
-- spin_lock(&hdev_list_lock);
-- if ((hdev = GET_HDEV(index)))
-- hci_dev_hold(hdev);
-- spin_unlock(&hdev_list_lock);
--
-- return hdev;
--}
--
--/* Flush inquiry cache */
--void inquiry_cache_flush(struct inquiry_cache *cache)
--{
-- struct inquiry_entry *next = cache->list, *e;
--
-- DBG("cache %p", cache);
--
-- cache->list = NULL;
-- while ((e = next)) {
-- next = e->next;
-- kfree(e);
-- }
--}
--
--/* Lookup by bdaddr.
-- * Cache must be locked. */
--static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
--{
-- struct inquiry_entry *e;
--
-- DBG("cache %p, %s", cache, batostr(bdaddr));
--
-- for (e = cache->list; e; e = e->next)
-- if (!bacmp(&e->info.bdaddr, bdaddr))
-- break;
--
-- return e;
--}
--
--static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
--{
-- struct inquiry_entry *e;
--
-- DBG("cache %p, %s", cache, batostr(&info->bdaddr));
--
-- inquiry_cache_lock(cache);
--
-- if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
-- /* Entry not in the cache. Add new one. */
-- if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
-- goto unlock;
-- memset(e, 0, sizeof(struct inquiry_entry));
-- e->next = cache->list;
-- cache->list = e;
-- }
--
-- memcpy(&e->info, info, sizeof(inquiry_info));
-- e->timestamp = jiffies;
-- cache->timestamp = jiffies;
--unlock:
-- inquiry_cache_unlock(cache);
--}
--
--static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
--{
-- inquiry_info *info = (inquiry_info *) buf;
-- struct inquiry_entry *e;
-- int copied = 0;
-+/* HCI protocols */
-+#define HCI_MAX_PROTO 2
-+struct hci_proto *hci_proto[HCI_MAX_PROTO];
-
-- inquiry_cache_lock(cache);
--
-- for (e = cache->list; e && copied < num; e = e->next, copied++)
-- memcpy(info++, &e->info, sizeof(inquiry_info));
-+/* HCI notifiers list */
-+static struct notifier_block *hci_notifier;
-
-- inquiry_cache_unlock(cache);
-
-- DBG("cache %p, copied %d", cache, copied);
-- return copied;
--}
-+/* ---- HCI notifications ---- */
-
--/* --------- BaseBand connections --------- */
--static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst)
-+int hci_register_notifier(struct notifier_block *nb)
- {
-- struct hci_conn *conn;
--
-- DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
--
-- if ( conn_hash_lookup(&hdev->conn_hash, handle)) {
-- ERR("%s handle 0x%x already exists", hdev->name, handle);
-- return NULL;
-- }
--
-- if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
-- return NULL;
-- memset(conn, 0, sizeof(struct hci_conn));
--
-- bacpy(&conn->dst, dst);
-- conn->handle = handle;
-- conn->type = type;
-- conn->hdev = hdev;
--
-- skb_queue_head_init(&conn->data_q);
--
-- hci_dev_hold(hdev);
-- conn_hash_add(&hdev->conn_hash, handle, conn);
--
-- return conn;
-+ return notifier_chain_register(&hci_notifier, nb);
- }
-
--static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
-+int hci_unregister_notifier(struct notifier_block *nb)
- {
-- DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
--
-- conn_hash_del(&hdev->conn_hash, conn);
-- hci_dev_put(hdev);
--
-- /* Unacked frames */
-- hdev->acl_cnt += conn->sent;
--
-- skb_queue_purge(&conn->data_q);
--
-- kfree(conn);
-- return 0;
-+ return notifier_chain_unregister(&hci_notifier, nb);
- }
-
--/* Drop all connection on the device */
--static void hci_conn_hash_flush(struct hci_dev *hdev)
-+void hci_notify(struct hci_dev *hdev, int event)
- {
-- struct conn_hash *h = &hdev->conn_hash;
-- struct hci_proto *hp;
-- struct list_head *p;
--
-- DBG("hdev %s", hdev->name);
--
-- p = h->list.next;
-- while (p != &h->list) {
-- struct hci_conn *c;
--
-- c = list_entry(p, struct hci_conn, list);
-- p = p->next;
--
-- if (c->type == ACL_LINK) {
-- /* ACL link notify L2CAP layer */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
-- hp->disconn_ind(c, 0x16);
-- } else {
-- /* SCO link (no notification) */
-- }
--
-- hci_conn_del(hdev, c);
-- }
-+ notifier_call_chain(&hci_notifier, event, hdev);
- }
-
--int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
--{
-- struct inquiry_cache *cache = &hdev->inq_cache;
-- struct inquiry_entry *e;
-- create_conn_cp cc;
-- __u16 clock_offset;
--
-- DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
--
-- if (!(hdev->flags & HCI_UP))
-- return -ENODEV;
--
-- inquiry_cache_lock_bh(cache);
--
-- if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
-- cc.pscan_rep_mode = 0;
-- cc.pscan_mode = 0;
-- clock_offset = 0;
-- } else {
-- cc.pscan_rep_mode = e->info.pscan_rep_mode;
-- cc.pscan_mode = e->info.pscan_mode;
-- clock_offset = __le16_to_cpu(e->info.clock_offset) & 0x8000;
-- }
--
-- inquiry_cache_unlock_bh(cache);
--
-- bacpy(&cc.bdaddr, bdaddr);
-- cc.pkt_type = __cpu_to_le16(hdev->pkt_type);
-- cc.clock_offset = __cpu_to_le16(clock_offset);
--
-- if (lmp_rswitch_capable(hdev))
-- cc.role_switch = 0x01;
-- else
-- cc.role_switch = 0x00;
--
-- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
-+/* ---- HCI hotplug support ---- */
-
-- return 0;
--}
-+#ifdef CONFIG_HOTPLUG
-
--int hci_disconnect(struct hci_conn *conn, __u8 reason)
-+static int hci_run_hotplug(char *dev, char *action)
- {
-- disconnect_cp dc;
--
-- DBG("conn %p handle %d", conn, conn->handle);
-+ char *argv[3], *envp[5], dstr[20], astr[32];
-
-- dc.handle = __cpu_to_le16(conn->handle);
-- dc.reason = reason;
-- hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
-+ sprintf(dstr, "DEVICE=%s", dev);
-+ sprintf(astr, "ACTION=%s", action);
-
-- return 0;
--}
-+ argv[0] = hotplug_path;
-+ argv[1] = "bluetooth";
-+ argv[2] = NULL;
-
--/* --------- HCI request handling ------------ */
--static inline void hci_req_lock(struct hci_dev *hdev)
--{
-- down(&hdev->req_lock);
-+ envp[0] = "HOME=/";
-+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+ envp[2] = dstr;
-+ envp[3] = astr;
-+ envp[4] = NULL;
-+
-+ return call_usermodehelper(argv[0], argv, envp);
- }
-+#else
-+#define hci_run_hotplug(A...)
-+#endif
-
--static inline void hci_req_unlock(struct hci_dev *hdev)
--{
-- up(&hdev->req_lock);
--}
-+/* ---- HCI requests ---- */
-
--static inline void hci_req_complete(struct hci_dev *hdev, int result)
-+void hci_req_complete(struct hci_dev *hdev, int result)
- {
-- DBG("%s result 0x%2.2x", hdev->name, result);
-+ BT_DBG("%s result 0x%2.2x", hdev->name, result);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = result;
-@@ -344,9 +134,9 @@
- }
- }
-
--static inline void hci_req_cancel(struct hci_dev *hdev, int err)
-+void hci_req_cancel(struct hci_dev *hdev, int err)
- {
-- DBG("%s err 0x%2.2x", hdev->name, err);
-+ BT_DBG("%s err 0x%2.2x", hdev->name, err);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = err;
-@@ -356,23 +146,22 @@
- }
-
- /* Execute request and wait for completion. */
--static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-- unsigned long opt, __u32 timeout)
-+static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout)
- {
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
-- DBG("%s start", hdev->name);
-+ BT_DBG("%s start", hdev->name);
-
- hdev->req_status = HCI_REQ_PEND;
-
- add_wait_queue(&hdev->req_wait_q, &wait);
-- current->state = TASK_INTERRUPTIBLE;
-+ set_current_state(TASK_INTERRUPTIBLE);
-
- req(hdev, opt);
- schedule_timeout(timeout);
-
-- current->state = TASK_RUNNING;
-+ set_current_state(TASK_RUNNING);
- remove_wait_queue(&hdev->req_wait_q, &wait);
-
- if (signal_pending(current))
-@@ -394,7 +183,7 @@
-
- hdev->req_status = hdev->req_result = 0;
-
-- DBG("%s end: err %d", hdev->name, err);
-+ BT_DBG("%s end: err %d", hdev->name, err);
-
- return err;
- }
-@@ -412,10 +201,9 @@
- return ret;
- }
-
--/* --------- HCI requests ---------- */
- static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
- {
-- DBG("%s %ld", hdev->name, opt);
-+ BT_DBG("%s %ld", hdev->name, opt);
-
- /* Reset device */
- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
-@@ -423,10 +211,10 @@
-
- static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
- {
-- set_event_flt_cp ec;
-+ set_event_flt_cp ef;
- __u16 param;
-
-- DBG("%s %ld", hdev->name, opt);
-+ BT_DBG("%s %ld", hdev->name, opt);
-
- /* Mandatory initialization */
-
-@@ -436,14 +224,30 @@
- /* Read Buffer Size (ACL mtu, max pkt, etc.) */
- hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
-
-+#if 0
-+ /* Host buffer size */
-+ {
-+ host_buffer_size_cp bs;
-+ bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
-+ bs.sco_mtu = HCI_MAX_SCO_SIZE;
-+ bs.acl_max_pkt = __cpu_to_le16(0xffff);
-+ bs.sco_max_pkt = __cpu_to_le16(0xffff);
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE,
-+ HOST_BUFFER_SIZE_CP_SIZE, &bs);
-+ }
-+#endif
-+
- /* Read BD Address */
- hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
-
-+ /* Read Voice Setting */
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
-+
- /* Optional initialization */
-
- /* Clear Event Filters */
-- ec.flt_type = FLT_CLEAR_ALL;
-- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec);
-+ ef.flt_type = FLT_CLEAR_ALL;
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef);
-
- /* Page timeout ~20 secs */
- param = __cpu_to_le16(0x8000);
-@@ -458,7 +262,7 @@
- {
- __u8 scan = opt;
-
-- DBG("%s %x", hdev->name, scan);
-+ BT_DBG("%s %x", hdev->name, scan);
-
- /* Inquiry and Page scans */
- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
-@@ -468,116 +272,272 @@
- {
- __u8 auth = opt;
-
-- DBG("%s %x", hdev->name, auth);
-+ BT_DBG("%s %x", hdev->name, auth);
-
- /* Authentication */
- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
- }
-
--static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
-+static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
- {
-- struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
-- inquiry_cp ic;
-+ __u8 encrypt = opt;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s %x", hdev->name, encrypt);
-
-- /* Start Inquiry */
-- memcpy(&ic.lap, &ir->lap, 3);
-- ic.lenght = ir->length;
-- ic.num_rsp = ir->num_rsp;
-- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
-+ /* Authentication */
-+ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
- }
-
--/* HCI ioctl helpers */
--int hci_dev_open(__u16 dev)
-+/* Get HCI device by index.
-+ * Device is locked on return. */
-+struct hci_dev *hci_dev_get(int index)
- {
- struct hci_dev *hdev;
-- int ret = 0;
--
-- if (!(hdev = hci_dev_get(dev)))
-- return -ENODEV;
-+ struct list_head *p;
-
-- DBG("%s %p", hdev->name, hdev);
-+ BT_DBG("%d", index);
-
-- hci_req_lock(hdev);
-+ if (index < 0)
-+ return NULL;
-
-- if (hdev->flags & HCI_UP) {
-- ret = -EALREADY;
-- goto done;
-+ read_lock(&hdev_list_lock);
-+ list_for_each(p, &hdev_list) {
-+ hdev = list_entry(p, struct hci_dev, list);
-+ if (hdev->id == index) {
-+ hci_dev_hold(hdev);
-+ goto done;
-+ }
- }
-+ hdev = NULL;
-+done:
-+ read_unlock(&hdev_list_lock);
-+ return hdev;
-+}
-
-- if (hdev->open(hdev)) {
-- ret = -EIO;
-- goto done;
-- }
-+/* ---- Inquiry support ---- */
-+void inquiry_cache_flush(struct hci_dev *hdev)
-+{
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ struct inquiry_entry *next = cache->list, *e;
-
-- if (hdev->flags & HCI_NORMAL) {
-- atomic_set(&hdev->cmd_cnt, 1);
-- hdev->flags |= HCI_INIT;
-+ BT_DBG("cache %p", cache);
-
-- //__hci_request(hdev, hci_reset_req, 0, HZ);
-- ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
--
-- hdev->flags &= ~HCI_INIT;
-+ cache->list = NULL;
-+ while ((e = next)) {
-+ next = e->next;
-+ kfree(e);
- }
-+}
-
-- if (!ret) {
-- hdev->flags |= HCI_UP;
-- hci_notify(hdev, HCI_DEV_UP);
-- } else {
-- /* Init failed, cleanup */
-- tasklet_kill(&hdev->rx_task);
-- tasklet_kill(&hdev->tx_task);
-- tasklet_kill(&hdev->cmd_task);
-+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-+{
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ struct inquiry_entry *e;
-
-- skb_queue_purge(&hdev->cmd_q);
-- skb_queue_purge(&hdev->rx_q);
-+ BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-
-- if (hdev->flush)
-- hdev->flush(hdev);
-+ for (e = cache->list; e; e = e->next)
-+ if (!bacmp(&e->info.bdaddr, bdaddr))
-+ break;
-+ return e;
-+}
-
-- if (hdev->sent_cmd) {
-- kfree_skb(hdev->sent_cmd);
-- hdev->sent_cmd = NULL;
-- }
-+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info)
-+{
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ struct inquiry_entry *e;
-
-- hdev->close(hdev);
-- }
-+ BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
-
--done:
-- hci_req_unlock(hdev);
-- hci_dev_put(hdev);
-+ if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
-+ /* Entry not in the cache. Add new one. */
-+ if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
-+ return;
-+ memset(e, 0, sizeof(struct inquiry_entry));
-+ e->next = cache->list;
-+ cache->list = e;
-+ }
-
-- return ret;
-+ memcpy(&e->info, info, sizeof(inquiry_info));
-+ e->timestamp = jiffies;
-+ cache->timestamp = jiffies;
- }
-
--int hci_dev_close(__u16 dev)
-+int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
- {
-- struct hci_dev *hdev;
--
-- if (!(hdev = hci_dev_get(dev)))
-- return -ENODEV;
-+ struct inquiry_cache *cache = &hdev->inq_cache;
-+ inquiry_info *info = (inquiry_info *) buf;
-+ struct inquiry_entry *e;
-+ int copied = 0;
-
-- DBG("%s %p", hdev->name, hdev);
-+ for (e = cache->list; e && copied < num; e = e->next, copied++)
-+ memcpy(info++, &e->info, sizeof(inquiry_info));
-
-- hci_req_cancel(hdev, ENODEV);
-- hci_req_lock(hdev);
-+ BT_DBG("cache %p, copied %d", cache, copied);
-+ return copied;
-+}
-
-- if (!(hdev->flags & HCI_UP))
-- goto done;
-+static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
-+{
-+ struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
-+ inquiry_cp ic;
-
-- /* Kill RX and TX tasks */
-- tasklet_kill(&hdev->rx_task);
-- tasklet_kill(&hdev->tx_task);
-+ BT_DBG("%s", hdev->name);
-
-- inquiry_cache_flush(&hdev->inq_cache);
-+ if (test_bit(HCI_INQUIRY, &hdev->flags))
-+ return;
-
-- hci_conn_hash_flush(hdev);
-+ /* Start Inquiry */
-+ memcpy(&ic.lap, &ir->lap, 3);
-+ ic.length = ir->length;
-+ ic.num_rsp = ir->num_rsp;
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
-+}
-
-- /* Clear flags */
-- hdev->flags &= HCI_SOCK;
-- hdev->flags |= HCI_NORMAL;
-+int hci_inquiry(unsigned long arg)
-+{
-+ struct hci_inquiry_req ir;
-+ struct hci_dev *hdev;
-+ int err = 0, do_inquiry = 0, max_rsp;
-+ long timeo;
-+ __u8 *buf, *ptr;
-
-+ ptr = (void *) arg;
-+ if (copy_from_user(&ir, ptr, sizeof(ir)))
-+ return -EFAULT;
-+
-+ if (!(hdev = hci_dev_get(ir.dev_id)))
-+ return -ENODEV;
-+
-+ hci_dev_lock_bh(hdev);
-+ if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-+ ir.flags & IREQ_CACHE_FLUSH) {
-+ inquiry_cache_flush(hdev);
-+ do_inquiry = 1;
-+ }
-+ hci_dev_unlock_bh(hdev);
-+
-+ timeo = ir.length * 2 * HZ;
-+ if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-+ goto done;
-+
-+ /* for unlimited number of responses we will use buffer with 255 entries */
-+ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
-+
-+ /* cache_dump can't sleep. Therefore we allocate temp buffer and then
-+ * copy it to the user space.
-+ */
-+ if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto done;
-+ }
-+
-+ hci_dev_lock_bh(hdev);
-+ ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
-+ hci_dev_unlock_bh(hdev);
-+
-+ BT_DBG("num_rsp %d", ir.num_rsp);
-+
-+ if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) +
-+ (sizeof(inquiry_info) * ir.num_rsp))) {
-+ copy_to_user(ptr, &ir, sizeof(ir));
-+ ptr += sizeof(ir);
-+ copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
-+ } else
-+ err = -EFAULT;
-+
-+ kfree(buf);
-+
-+done:
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
-+/* ---- HCI ioctl helpers ---- */
-+
-+int hci_dev_open(__u16 dev)
-+{
-+ struct hci_dev *hdev;
-+ int ret = 0;
-+
-+ if (!(hdev = hci_dev_get(dev)))
-+ return -ENODEV;
-+
-+ BT_DBG("%s %p", hdev->name, hdev);
-+
-+ hci_req_lock(hdev);
-+
-+ if (test_bit(HCI_UP, &hdev->flags)) {
-+ ret = -EALREADY;
-+ goto done;
-+ }
-+
-+ if (hdev->open(hdev)) {
-+ ret = -EIO;
-+ goto done;
-+ }
-+
-+ if (!test_bit(HCI_RAW, &hdev->flags)) {
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ set_bit(HCI_INIT, &hdev->flags);
-+
-+ //__hci_request(hdev, hci_reset_req, 0, HZ);
-+ ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
-+
-+ clear_bit(HCI_INIT, &hdev->flags);
-+ }
-+
-+ if (!ret) {
-+ set_bit(HCI_UP, &hdev->flags);
-+ hci_notify(hdev, HCI_DEV_UP);
-+ } else {
-+ /* Init failed, cleanup */
-+ tasklet_kill(&hdev->rx_task);
-+ tasklet_kill(&hdev->tx_task);
-+ tasklet_kill(&hdev->cmd_task);
-+
-+ skb_queue_purge(&hdev->cmd_q);
-+ skb_queue_purge(&hdev->rx_q);
-+
-+ if (hdev->flush)
-+ hdev->flush(hdev);
-+
-+ if (hdev->sent_cmd) {
-+ kfree_skb(hdev->sent_cmd);
-+ hdev->sent_cmd = NULL;
-+ }
-+
-+ hdev->close(hdev);
-+ hdev->flags = 0;
-+ }
-+
-+done:
-+ hci_req_unlock(hdev);
-+ hci_dev_put(hdev);
-+ return ret;
-+}
-+
-+static int hci_dev_do_close(struct hci_dev *hdev)
-+{
-+ BT_DBG("%s %p", hdev->name, hdev);
-+
-+ hci_req_cancel(hdev, ENODEV);
-+ hci_req_lock(hdev);
-+
-+ if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
-+ hci_req_unlock(hdev);
-+ return 0;
-+ }
-+
-+ /* Kill RX and TX tasks */
-+ tasklet_kill(&hdev->rx_task);
-+ tasklet_kill(&hdev->tx_task);
-+
-+ hci_dev_lock_bh(hdev);
-+ inquiry_cache_flush(hdev);
-+ hci_conn_hash_flush(hdev);
-+ hci_dev_unlock_bh(hdev);
-+
- hci_notify(hdev, HCI_DEV_DOWN);
-
- if (hdev->flush)
-@@ -586,9 +546,9 @@
- /* Reset device */
- skb_queue_purge(&hdev->cmd_q);
- atomic_set(&hdev->cmd_cnt, 1);
-- hdev->flags |= HCI_INIT;
-- __hci_request(hdev, hci_reset_req, 0, HZ);
-- hdev->flags &= ~HCI_INIT;
-+ set_bit(HCI_INIT, &hdev->flags);
-+ __hci_request(hdev, hci_reset_req, 0, HZ/4);
-+ clear_bit(HCI_INIT, &hdev->flags);
-
- /* Kill cmd task */
- tasklet_kill(&hdev->cmd_task);
-@@ -605,17 +565,28 @@
- }
-
- /* After this point our queues are empty
-- * and no tasks are scheduled.
-- */
-+ * and no tasks are scheduled. */
- hdev->close(hdev);
-
--done:
-- hci_req_unlock(hdev);
-- hci_dev_put(hdev);
-+ /* Clear flags */
-+ hdev->flags = 0;
-
-+ hci_req_unlock(hdev);
- return 0;
- }
-
-+int hci_dev_close(__u16 dev)
-+{
-+ struct hci_dev *hdev;
-+ int err;
-+
-+ if (!(hdev = hci_dev_get(dev)))
-+ return -ENODEV;
-+ err = hci_dev_do_close(hdev);
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
- int hci_dev_reset(__u16 dev)
- {
- struct hci_dev *hdev;
-@@ -627,16 +598,17 @@
- hci_req_lock(hdev);
- tasklet_disable(&hdev->tx_task);
-
-- if (!(hdev->flags & HCI_UP))
-+ if (!test_bit(HCI_UP, &hdev->flags))
- goto done;
-
- /* Drop queues */
- skb_queue_purge(&hdev->rx_q);
- skb_queue_purge(&hdev->cmd_q);
-
-- inquiry_cache_flush(&hdev->inq_cache);
--
-+ hci_dev_lock_bh(hdev);
-+ inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
-+ hci_dev_unlock_bh(hdev);
-
- if (hdev->flush)
- hdev->flush(hdev);
-@@ -650,7 +622,6 @@
- tasklet_enable(&hdev->tx_task);
- hci_req_unlock(hdev);
- hci_dev_put(hdev);
--
- return ret;
- }
-
-@@ -669,30 +640,11 @@
- return ret;
- }
-
--int hci_dev_setauth(unsigned long arg)
--{
-- struct hci_dev *hdev;
-- struct hci_dev_req dr;
-- int ret = 0;
--
-- if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-- return -EFAULT;
--
-- if (!(hdev = hci_dev_get(dr.dev_id)))
-- return -ENODEV;
--
-- ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
--
-- hci_dev_put(hdev);
--
-- return ret;
--}
--
--int hci_dev_setscan(unsigned long arg)
-+int hci_dev_cmd(unsigned int cmd, unsigned long arg)
- {
- struct hci_dev *hdev;
- struct hci_dev_req dr;
-- int ret = 0;
-+ int err = 0;
-
- if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
- return -EFAULT;
-@@ -700,48 +652,78 @@
- if (!(hdev = hci_dev_get(dr.dev_id)))
- return -ENODEV;
-
-- ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
--
-- hci_dev_put(hdev);
-+ switch (cmd) {
-+ case HCISETAUTH:
-+ err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-+ break;
-
-- return ret;
--}
-+ case HCISETENCRYPT:
-+ if (!lmp_encrypt_capable(hdev)) {
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-
--int hci_dev_setptype(unsigned long arg)
--{
-- struct hci_dev *hdev;
-- struct hci_dev_req dr;
-- int ret = 0;
-+ if (!test_bit(HCI_AUTH, &hdev->flags)) {
-+ /* Auth must be enabled first */
-+ err = hci_request(hdev, hci_auth_req,
-+ dr.dev_opt, HCI_INIT_TIMEOUT);
-+ if (err)
-+ break;
-+ }
-+
-+ err = hci_request(hdev, hci_encrypt_req,
-+ dr.dev_opt, HCI_INIT_TIMEOUT);
-+ break;
-+
-+ case HCISETSCAN:
-+ err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-+ break;
-+
-+ case HCISETPTYPE:
-+ hdev->pkt_type = (__u16) dr.dev_opt;
-+ break;
-+
-+ case HCISETLINKPOL:
-+ hdev->link_policy = (__u16) dr.dev_opt;
-+ break;
-
-- if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-- return -EFAULT;
-+ case HCISETLINKMODE:
-+ hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
-+ break;
-
-- if (!(hdev = hci_dev_get(dr.dev_id)))
-- return -ENODEV;
-+ case HCISETACLMTU:
-+ hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1);
-+ hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
-+ break;
-
-- hdev->pkt_type = (__u16) dr.dev_opt;
-+ case HCISETSCOMTU:
-+ hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1);
-+ hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
-+ break;
-
-+ default:
-+ err = -EINVAL;
-+ break;
-+ }
- hci_dev_put(hdev);
--
-- return ret;
-+ return err;
- }
-
--int hci_dev_list(unsigned long arg)
-+int hci_get_dev_list(unsigned long arg)
- {
- struct hci_dev_list_req *dl;
- struct hci_dev_req *dr;
-- struct hci_dev *hdev;
-- int i, n, size;
-+ struct list_head *p;
-+ int n = 0, size;
- __u16 dev_num;
-
- if (get_user(dev_num, (__u16 *) arg))
- return -EFAULT;
-
-- /* Avoid long loop, overflow */
-- if (dev_num > 2048)
-+ if (!dev_num)
- return -EINVAL;
-
-- size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
-+ size = dev_num * sizeof(*dr) + sizeof(*dl);
-
- if (verify_area(VERIFY_WRITE, (void *) arg, size))
- return -EFAULT;
-@@ -750,25 +732,27 @@
- return -ENOMEM;
- dr = dl->dev_req;
-
-- spin_lock_bh(&hdev_list_lock);
-- for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
-- if ((hdev = hdev_list[i])) {
-- (dr + n)->dev_id = hdev->id;
-- (dr + n)->dev_opt = hdev->flags;
-- n++;
-- }
-+ read_lock_bh(&hdev_list_lock);
-+ list_for_each(p, &hdev_list) {
-+ struct hci_dev *hdev;
-+ hdev = list_entry(p, struct hci_dev, list);
-+ (dr + n)->dev_id = hdev->id;
-+ (dr + n)->dev_opt = hdev->flags;
-+ if (++n >= dev_num)
-+ break;
- }
-- spin_unlock_bh(&hdev_list_lock);
-+ read_unlock_bh(&hdev_list_lock);
-
- dl->dev_num = n;
-- size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
-+ size = n * sizeof(*dr) + sizeof(*dl);
-
- copy_to_user((void *) arg, dl, size);
-+ kfree(dl);
-
- return 0;
- }
-
--int hci_dev_info(unsigned long arg)
-+int hci_get_dev_info(unsigned long arg)
- {
- struct hci_dev *hdev;
- struct hci_dev_info di;
-@@ -786,9 +770,11 @@
- di.flags = hdev->flags;
- di.pkt_type = hdev->pkt_type;
- di.acl_mtu = hdev->acl_mtu;
-- di.acl_max = hdev->acl_max;
-+ di.acl_pkts = hdev->acl_pkts;
- di.sco_mtu = hdev->sco_mtu;
-- di.sco_max = hdev->sco_max;
-+ di.sco_pkts = hdev->sco_pkts;
-+ di.link_policy = hdev->link_policy;
-+ di.link_mode = hdev->link_mode;
-
- memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
- memcpy(&di.features, &hdev->features, sizeof(di.features));
-@@ -801,258 +787,168 @@
- return err;
- }
-
--__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
--{
-- __u32 omode = hdev->flags & HCI_MODE_MASK;
--
-- hdev->flags &= ~HCI_MODE_MASK;
-- hdev->flags |= (mode & HCI_MODE_MASK);
-
-- return omode;
--}
-+/* ---- Interface to HCI drivers ---- */
-
--__u32 hci_dev_getmode(struct hci_dev *hdev)
-+/* Register HCI device */
-+int hci_register_dev(struct hci_dev *hdev)
- {
-- return hdev->flags & HCI_MODE_MASK;
--}
-+ struct list_head *head = &hdev_list, *p;
-+ int id = 0;
-
--int hci_conn_list(unsigned long arg)
--{
-- struct hci_conn_list_req req, *cl;
-- struct hci_conn_info *ci;
-- struct hci_dev *hdev;
-- struct list_head *p;
-- int n = 0, size;
-+ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-
-- if (copy_from_user(&req, (void *) arg, sizeof(req)))
-- return -EFAULT;
-+ if (!hdev->open || !hdev->close || !hdev->destruct)
-+ return -EINVAL;
-
-- if (!(hdev = hci_dev_get(req.dev_id)))
-- return -ENODEV;
-+ write_lock_bh(&hdev_list_lock);
-
-- /* Set a limit to avoid overlong loops, and also numeric overflow - AC */
-- if(req.conn_num < 2048)
-- return -EINVAL;
-+ /* Find first available device id */
-+ list_for_each(p, &hdev_list) {
-+ if (list_entry(p, struct hci_dev, list)->id != id)
-+ break;
-+ head = p; id++;
-+ }
-
-- size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
--
-- if (!(cl = kmalloc(size, GFP_KERNEL)))
-- return -ENOMEM;
-- ci = cl->conn_info;
-+ sprintf(hdev->name, "hci%d", id);
-+ hdev->id = id;
-+ list_add(&hdev->list, head);
-
-- local_bh_disable();
-- conn_hash_lock(&hdev->conn_hash);
-- list_for_each(p, &hdev->conn_hash.list) {
-- register struct hci_conn *c;
-- c = list_entry(p, struct hci_conn, list);
-+ atomic_set(&hdev->refcnt, 1);
-+ spin_lock_init(&hdev->lock);
-+
-+ hdev->flags = 0;
-+ hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
-+ hdev->link_mode = (HCI_LM_ACCEPT);
-
-- (ci + n)->handle = c->handle;
-- bacpy(&(ci + n)->bdaddr, &c->dst);
-- n++;
-- }
-- conn_hash_unlock(&hdev->conn_hash);
-- local_bh_enable();
--
-- cl->dev_id = hdev->id;
-- cl->conn_num = n;
-- size = n * sizeof(struct hci_conn_info) + sizeof(req);
-+ tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
-+ tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
-+ tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
-
-- hci_dev_put(hdev);
-+ skb_queue_head_init(&hdev->rx_q);
-+ skb_queue_head_init(&hdev->cmd_q);
-+ skb_queue_head_init(&hdev->raw_q);
-
-- if(copy_to_user((void *) arg, cl, size))
-- return -EFAULT;
-- return 0;
--}
-+ init_waitqueue_head(&hdev->req_wait_q);
-+ init_MUTEX(&hdev->req_lock);
-
--int hci_inquiry(unsigned long arg)
--{
-- struct inquiry_cache *cache;
-- struct hci_inquiry_req ir;
-- struct hci_dev *hdev;
-- int err = 0, do_inquiry = 0;
-- long timeo;
-- __u8 *buf, *ptr;
-+ inquiry_cache_init(hdev);
-
-- ptr = (void *) arg;
-- if (copy_from_user(&ir, ptr, sizeof(ir)))
-- return -EFAULT;
-+ conn_hash_init(hdev);
-
-- if (!(hdev = hci_dev_get(ir.dev_id)))
-- return -ENODEV;
-+ memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-
-- cache = &hdev->inq_cache;
-+ atomic_set(&hdev->promisc, 0);
-
-- inquiry_cache_lock(cache);
-- if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
-- inquiry_cache_flush(cache);
-- do_inquiry = 1;
-- }
-- inquiry_cache_unlock(cache);
-+ MOD_INC_USE_COUNT;
-
-- /* Limit inquiry time, also avoid overflows */
-+ write_unlock_bh(&hdev_list_lock);
-
-- if(ir.length > 2048 || ir.num_rsp > 2048)
-- {
-- err = -EINVAL;
-- goto done;
-- }
-+ hci_notify(hdev, HCI_DEV_REG);
-+ hci_run_hotplug(hdev->name, "register");
-
-- timeo = ir.length * 2 * HZ;
-- if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-- goto done;
-+ return id;
-+}
-
-- /* cache_dump can't sleep. Therefore we allocate temp buffer and then
-- * copy it to the user space.
-- */
-- if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
-- err = -ENOMEM;
-- goto done;
-- }
-- ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
-+/* Unregister HCI device */
-+int hci_unregister_dev(struct hci_dev *hdev)
-+{
-+ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-
-- DBG("num_rsp %d", ir.num_rsp);
-+ write_lock_bh(&hdev_list_lock);
-+ list_del(&hdev->list);
-+ write_unlock_bh(&hdev_list_lock);
-
-- if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
-- copy_to_user(ptr, &ir, sizeof(ir));
-- ptr += sizeof(ir);
-- copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
-- } else
-- err = -EFAULT;
-+ hci_dev_do_close(hdev);
-
-- kfree(buf);
-+ hci_notify(hdev, HCI_DEV_UNREG);
-+ hci_run_hotplug(hdev->name, "unregister");
-
--done:
- hci_dev_put(hdev);
-
-- return err;
-+ MOD_DEC_USE_COUNT;
-+ return 0;
- }
-
--/* Interface to HCI drivers */
--
--/* Register HCI device */
--int hci_register_dev(struct hci_dev *hdev)
-+/* Suspend HCI device */
-+int hci_suspend_dev(struct hci_dev *hdev)
- {
-- int i;
--
-- DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
--
-- /* Find free slot */
-- spin_lock_bh(&hdev_list_lock);
-- for (i = 0; i < HCI_MAX_DEV; i++) {
-- if (!hdev_list[i]) {
-- hdev_list[i] = hdev;
-+ hci_notify(hdev, HCI_DEV_SUSPEND);
-+ hci_run_hotplug(hdev->name, "suspend");
-+ return 0;
-+}
-
-- sprintf(hdev->name, "hci%d", i);
-- atomic_set(&hdev->refcnt, 0);
-- hdev->id = i;
-- hdev->flags = HCI_NORMAL;
-+/* Resume HCI device */
-+int hci_resume_dev(struct hci_dev *hdev)
-+{
-+ hci_notify(hdev, HCI_DEV_RESUME);
-+ hci_run_hotplug(hdev->name, "resume");
-+ return 0;
-+}
-
-- hdev->pkt_type = (HCI_DM1 | HCI_DH1);
--
-- tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
-- tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
-- tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
--
-- skb_queue_head_init(&hdev->rx_q);
-- skb_queue_head_init(&hdev->cmd_q);
-- skb_queue_head_init(&hdev->raw_q);
--
-- init_waitqueue_head(&hdev->req_wait_q);
-- init_MUTEX(&hdev->req_lock);
--
-- inquiry_cache_init(&hdev->inq_cache);
--
-- conn_hash_init(&hdev->conn_hash);
--
-- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
--
-- hci_notify(hdev, HCI_DEV_REG);
--
-- MOD_INC_USE_COUNT;
-- break;
-- }
-- }
-- spin_unlock_bh(&hdev_list_lock);
--
-- return (i == HCI_MAX_DEV) ? -1 : i;
--}
--
--/* Unregister HCI device */
--int hci_unregister_dev(struct hci_dev *hdev)
-+/* Receive frame from HCI drivers */
-+int hci_recv_frame(struct sk_buff *skb)
- {
-- int i;
--
-- DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
--
-- if (hdev->flags & HCI_UP)
-- hci_dev_close(hdev->id);
-+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-
-- /* Find device slot */
-- spin_lock(&hdev_list_lock);
-- for (i = 0; i < HCI_MAX_DEV; i++) {
-- if (hdev_list[i] == hdev) {
-- hdev_list[i] = NULL;
-- MOD_DEC_USE_COUNT;
-- break;
-- }
-+ if (!hdev || (!test_bit(HCI_UP, &hdev->flags) &&
-+ !test_bit(HCI_INIT, &hdev->flags)) ) {
-+ kfree_skb(skb);
-+ return -1;
- }
-- spin_unlock(&hdev_list_lock);
--
-- hci_notify(hdev, HCI_DEV_UNREG);
-
-- /* Sleep while device is in use */
-- while (atomic_read(&hdev->refcnt)) {
-- int sleep_cnt = 100;
-+ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-- DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
-+ /* Incomming skb */
-+ bluez_cb(skb)->incomming = 1;
-
-- sleep_on_timeout(&hdev->req_wait_q, HZ*10);
-- if (!(--sleep_cnt))
-- break;
-- }
-+ /* Time stamp */
-+ do_gettimeofday(&skb->stamp);
-
-+ /* Queue frame for rx task */
-+ skb_queue_tail(&hdev->rx_q, skb);
-+ hci_sched_rx(hdev);
- return 0;
- }
-
--/* Interface to upper protocols */
-+/* ---- Interface to upper protocols ---- */
-
- /* Register/Unregister protocols.
-- * hci_task_lock is used to ensure that no tasks are running.
-- */
--int hci_register_proto(struct hci_proto *hproto)
-+ * hci_task_lock is used to ensure that no tasks are running. */
-+int hci_register_proto(struct hci_proto *hp)
- {
- int err = 0;
-
-- DBG("%p name %s", hproto, hproto->name);
-+ BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
-
-- if (hproto->id >= HCI_MAX_PROTO)
-+ if (hp->id >= HCI_MAX_PROTO)
- return -EINVAL;
-
- write_lock_bh(&hci_task_lock);
-
-- if (!hproto_list[hproto->id])
-- hproto_list[hproto->id] = hproto;
-+ if (!hci_proto[hp->id])
-+ hci_proto[hp->id] = hp;
- else
-- err = -1;
-+ err = -EEXIST;
-
- write_unlock_bh(&hci_task_lock);
-
- return err;
- }
-
--int hci_unregister_proto(struct hci_proto *hproto)
-+int hci_unregister_proto(struct hci_proto *hp)
- {
- int err = 0;
-
-- DBG("%p name %s", hproto, hproto->name);
-+ BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
-
-- if (hproto->id > HCI_MAX_PROTO)
-+ if (hp->id >= HCI_MAX_PROTO)
- return -EINVAL;
-
- write_lock_bh(&hci_task_lock);
-
-- if (hproto_list[hproto->id])
-- hproto_list[hproto->id] = NULL;
-+ if (hci_proto[hp->id])
-+ hci_proto[hp->id] = NULL;
- else
- err = -ENOENT;
-
-@@ -1070,10 +966,14 @@
- return -ENODEV;
- }
-
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+
-+ if (atomic_read(&hdev->promisc)) {
-+ /* Time stamp */
-+ do_gettimeofday(&skb->stamp);
-
-- if (hdev->flags & HCI_SOCK)
- hci_send_to_sock(hdev, skb);
-+ }
-
- /* Get rid of skb owner, prior to sending to the driver. */
- skb_orphan(skb);
-@@ -1081,128 +981,6 @@
- return hdev->send(skb);
- }
-
--/* Connection scheduler */
--static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
--{
-- struct conn_hash *h = &hdev->conn_hash;
-- struct hci_conn *conn = NULL;
-- int num = 0, min = 0xffff;
-- struct list_head *p;
--
-- conn_hash_lock(h);
-- list_for_each(p, &h->list) {
-- register struct hci_conn *c;
--
-- c = list_entry(p, struct hci_conn, list);
--
-- if (c->type != type || skb_queue_empty(&c->data_q))
-- continue;
-- num++;
--
-- if (c->sent < min) {
-- min = c->sent;
-- conn = c;
-- }
-- }
-- conn_hash_unlock(h);
--
-- if (conn) {
-- int q = hdev->acl_cnt / num;
-- *quote = q ? q : 1;
-- } else
-- *quote = 0;
--
-- DBG("conn %p quote %d", conn, *quote);
--
-- return conn;
--}
--
--static inline void hci_sched_acl(struct hci_dev *hdev)
--{
-- struct hci_conn *conn;
-- struct sk_buff *skb;
-- int quote;
--
-- DBG("%s", hdev->name);
--
-- while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-- while (quote && (skb = skb_dequeue(&conn->data_q))) {
-- DBG("skb %p len %d", skb, skb->len);
--
-- hci_send_frame(skb);
--
-- conn->sent++;
-- hdev->acl_cnt--;
-- quote--;
-- }
-- }
--}
--
--/* Schedule SCO */
--static inline void hci_sched_sco(struct hci_dev *hdev)
--{
-- /* FIXME: For now we queue SCO packets to the raw queue
--
-- while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) {
-- hci_send_frame(skb);
-- conn->sco_sent++;
-- hdev->sco_cnt--;
-- }
-- */
--}
--
--/* Get data from the previously sent command */
--static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
--{
-- hci_command_hdr *hc;
--
-- if (!hdev->sent_cmd)
-- return NULL;
--
-- hc = (void *) hdev->sent_cmd->data;
--
-- if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
-- return NULL;
--
-- DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
--
-- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
--}
--
--/* Send raw HCI frame */
--int hci_send_raw(struct sk_buff *skb)
--{
-- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--
-- if (!hdev) {
-- kfree_skb(skb);
-- return -ENODEV;
-- }
--
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
-- if (hdev->flags & HCI_NORMAL) {
-- /* Queue frame according it's type */
-- switch (skb->pkt_type) {
-- case HCI_COMMAND_PKT:
-- skb_queue_tail(&hdev->cmd_q, skb);
-- hci_sched_cmd(hdev);
-- return 0;
--
-- case HCI_ACLDATA_PKT:
-- case HCI_SCODATA_PKT:
-- /* FIXME:
-- * Check header here and queue to apropriate connection.
-- */
-- break;
-- }
-- }
--
-- skb_queue_tail(&hdev->raw_q, skb);
-- hci_sched_tx(hdev);
-- return 0;
--}
--
- /* Send HCI command */
- int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
- {
-@@ -1210,10 +988,10 @@
- hci_command_hdr *hc;
- struct sk_buff *skb;
-
-- DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
-+ BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
-
- if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
-- ERR("%s Can't allocate memory for HCI command", hdev->name);
-+ BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
- return -ENOMEM;
- }
-
-@@ -1224,7 +1002,7 @@
- if (plen)
- memcpy(skb_put(skb, plen), param, plen);
-
-- DBG("skb len %d", skb->len);
-+ BT_DBG("skb len %d", skb->len);
-
- skb->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-@@ -1234,10 +1012,28 @@
- return 0;
- }
-
-+/* Get data from the previously sent command */
-+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
-+{
-+ hci_command_hdr *hc;
-+
-+ if (!hdev->sent_cmd)
-+ return NULL;
-+
-+ hc = (void *) hdev->sent_cmd->data;
-+
-+ if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
-+ return NULL;
-+
-+ BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
-+
-+ return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
-+}
-+
- /* Send ACL data */
- static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
- {
-- int len = skb->len;
-+ int len = skb->len;
- hci_acl_hdr *ah;
-
- ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
-@@ -1252,7 +1048,7 @@
- struct hci_dev *hdev = conn->hdev;
- struct sk_buff *list;
-
-- DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-+ BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-
- skb->dev = (void *) hdev;
- skb->pkt_type = HCI_ACLDATA_PKT;
-@@ -1260,12 +1056,12 @@
-
- if (!(list = skb_shinfo(skb)->frag_list)) {
- /* Non fragmented */
-- DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-+ BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-
- skb_queue_tail(&conn->data_q, skb);
- } else {
- /* Fragmented */
-- DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-+ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- skb_shinfo(skb)->frag_list = NULL;
-
-@@ -1280,7 +1076,7 @@
- skb->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
-
-- DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-+ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- __skb_queue_tail(&conn->data_q, skb);
- } while (list);
-@@ -1298,7 +1094,7 @@
- struct hci_dev *hdev = conn->hdev;
- hci_sco_hdr hs;
-
-- DBG("%s len %d", hdev->name, skb->len);
-+ BT_DBG("%s len %d", hdev->name, skb->len);
-
- if (skb->len > hdev->sco_mtu) {
- kfree_skb(skb);
-@@ -1315,544 +1111,136 @@
- skb->pkt_type = HCI_SCODATA_PKT;
- skb_queue_tail(&conn->data_q, skb);
- hci_sched_tx(hdev);
--
- return 0;
- }
-
--/* Handle HCI Event packets */
--
--/* Command Complete OGF LINK_CTL */
--static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Complete OGF LINK_POLICY */
--static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Complete OGF HOST_CTL */
--static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
-- __u8 status, param;
-- void *sent;
--
--
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- case OCF_RESET:
-- status = *((__u8 *) skb->data);
--
-- hci_req_complete(hdev, status);
-- break;
--
-- case OCF_SET_EVENT_FLT:
-- status = *((__u8 *) skb->data);
--
-- if (status) {
-- DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-- } else {
-- DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-- }
-- break;
--
-- case OCF_WRITE_AUTH_ENABLE:
-- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE)))
-- break;
--
-- status = *((__u8 *) skb->data);
-- param = *((__u8 *) sent);
-+/* ---- HCI TX task (outgoing data) ---- */
-
-- if (!status) {
-- if (param == AUTH_ENABLED)
-- hdev->flags |= HCI_AUTH;
-- else
-- hdev->flags &= ~HCI_AUTH;
-- }
-- hci_req_complete(hdev, status);
-- break;
--
-- case OCF_WRITE_CA_TIMEOUT:
-- status = *((__u8 *) skb->data);
--
-- if (status) {
-- DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-- } else {
-- DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-- }
-- break;
--
-- case OCF_WRITE_PG_TIMEOUT:
-- status = *((__u8 *) skb->data);
--
-- if (status) {
-- DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-- } else {
-- DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-- }
-- break;
--
-- case OCF_WRITE_SCAN_ENABLE:
-- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE)))
-- break;
-- status = *((__u8 *) skb->data);
-- param = *((__u8 *) sent);
--
-- DBG("param 0x%x", param);
--
-- if (!status) {
-- switch (param) {
-- case IS_ENA_PS_ENA:
-- hdev->flags |= HCI_PSCAN | HCI_ISCAN;
-- break;
--
-- case IS_ENA_PS_DIS:
-- hdev->flags &= ~HCI_PSCAN;
-- hdev->flags |= HCI_ISCAN;
-- break;
--
-- case IS_DIS_PS_ENA:
-- hdev->flags &= ~HCI_ISCAN;
-- hdev->flags |= HCI_PSCAN;
-- break;
--
-- default:
-- hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
-- break;
-- };
-- }
-- hci_req_complete(hdev, status);
-- break;
--
-- default:
-- DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Complete OGF INFO_PARAM */
--static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+/* HCI Connection scheduler */
-+static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
- {
-- read_local_features_rp *lf;
-- read_buffer_size_rp *bs;
-- read_bd_addr_rp *ba;
--
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- case OCF_READ_LOCAL_FEATURES:
-- lf = (read_local_features_rp *) skb->data;
--
-- if (lf->status) {
-- DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-- break;
-- }
--
-- memcpy(hdev->features, lf->features, sizeof(hdev->features));
--
-- /* Adjust default settings according to features
-- * supported by device. */
-- if (hdev->features[0] & LMP_3SLOT)
-- hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
--
-- if (hdev->features[0] & LMP_5SLOT)
-- hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
--
-- DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
--
-- break;
--
-- case OCF_READ_BUFFER_SIZE:
-- bs = (read_buffer_size_rp *) skb->data;
--
-- if (bs->status) {
-- DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-- break;
-- }
--
-- hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
-- hdev->sco_mtu = bs->sco_mtu;
-- hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-- hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
--
-- DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-- hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
-+ struct conn_hash *h = &hdev->conn_hash;
-+ struct hci_conn *conn = NULL;
-+ int num = 0, min = ~0;
-+ struct list_head *p;
-
-- break;
-+ /* We don't have to lock device here. Connections are always
-+ * added and removed with TX task disabled. */
-+ list_for_each(p, &h->list) {
-+ struct hci_conn *c;
-+ c = list_entry(p, struct hci_conn, list);
-
-- case OCF_READ_BD_ADDR:
-- ba = (read_bd_addr_rp *) skb->data;
-+ if (c->type != type || c->state != BT_CONNECTED
-+ || skb_queue_empty(&c->data_q))
-+ continue;
-+ num++;
-
-- if (!ba->status) {
-- bacpy(&hdev->bdaddr, &ba->bdaddr);
-- } else {
-- DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-+ if (c->sent < min) {
-+ min = c->sent;
-+ conn = c;
- }
-+ }
-
-- hci_req_complete(hdev, ba->status);
-- break;
-+ if (conn) {
-+ int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
-+ int q = cnt / num;
-+ *quote = q ? q : 1;
-+ } else
-+ *quote = 0;
-
-- default:
-- DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-- break;
-- };
-+ BT_DBG("conn %p quote %d", conn, *quote);
-+ return conn;
- }
-
--/* Command Status OGF LINK_CTL */
--static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+static inline void hci_acl_tx_to(struct hci_dev *hdev)
- {
-- struct hci_proto * hp;
--
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- case OCF_CREATE_CONN:
-- if (status) {
-- create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
--
-- if (!cc)
-- break;
--
-- DBG("%s Create connection error: status 0x%x %s", hdev->name,
-- status, batostr(&cc->bdaddr));
-+ struct conn_hash *h = &hdev->conn_hash;
-+ struct list_head *p;
-+ struct hci_conn *c;
-
-- /* Notify upper protocols */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
-- tasklet_disable(&hdev->tx_task);
-- hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
-- tasklet_enable(&hdev->tx_task);
-- }
-- }
-- break;
-+ BT_ERR("%s ACL tx timeout", hdev->name);
-
-- case OCF_INQUIRY:
-- if (status) {
-- DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-- hci_req_complete(hdev, status);
-+ /* Kill stalled connections */
-+ list_for_each(p, &h->list) {
-+ c = list_entry(p, struct hci_conn, list);
-+ if (c->type == ACL_LINK && c->sent) {
-+ BT_ERR("%s killing stalled ACL connection %s",
-+ hdev->name, batostr(&c->dst));
-+ hci_acl_disconn(c, 0x13);
- }
-- break;
--
-- default:
-- DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Status OGF LINK_POLICY */
--static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Status OGF HOST_CTL */
--static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
-- DBG("%s ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Command Status OGF INFO_PARAM */
--static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
-- DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
--
-- switch (ocf) {
-- default:
-- DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-- break;
-- };
--}
--
--/* Inquiry Complete */
--static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- __u8 status = *((__u8 *) skb->data);
--
-- DBG("%s status %d", hdev->name, status);
--
-- hci_req_complete(hdev, status);
-+ }
- }
-
--/* Inquiry Result */
--static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static inline void hci_sched_acl(struct hci_dev *hdev)
- {
-- inquiry_info *info = (inquiry_info *) (skb->data + 1);
-- int num_rsp = *((__u8 *) skb->data);
--
-- DBG("%s num_rsp %d", hdev->name, num_rsp);
-+ struct hci_conn *conn;
-+ struct sk_buff *skb;
-+ int quote;
-
-- for (; num_rsp; num_rsp--)
-- inquiry_cache_update(&hdev->inq_cache, info++);
--}
-+ BT_DBG("%s", hdev->name);
-
--/* Connect Request */
--static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- evt_conn_request *cr = (evt_conn_request *) skb->data;
-- struct hci_proto *hp;
-- accept_conn_req_cp ac;
-- int accept = 0;
-+ /* ACL tx timeout must be longer than maximum
-+ * link supervision timeout (40.9 seconds) */
-+ if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
-+ hci_acl_tx_to(hdev);
-
-- DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type);
-+ while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-+ BT_DBG("skb %p len %d", skb, skb->len);
-+ hci_send_frame(skb);
-+ hdev->acl_last_tx = jiffies;
-
-- /* Notify upper protocols */
-- if (cr->link_type == ACL_LINK) {
-- /* ACL link notify L2CAP */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
-- tasklet_disable(&hdev->tx_task);
-- accept = hp->connect_ind(hdev, &cr->bdaddr);
-- tasklet_enable(&hdev->tx_task);
-+ hdev->acl_cnt--;
-+ conn->sent++;
- }
-- } else {
-- /* SCO link (no notification) */
-- /* FIXME: Should be accept it here or let the requester (app) accept it ? */
-- accept = 1;
-- }
--
-- if (accept) {
-- /* Connection accepted by upper layer */
-- bacpy(&ac.bdaddr, &cr->bdaddr);
-- ac.role = 0x01; /* Remain slave */
-- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
-- } else {
-- /* Connection rejected by upper layer */
-- /* FIXME:
-- * Should we use HCI reject here ?
-- */
-- return;
- }
- }
-
--/* Connect Complete */
--static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+/* Schedule SCO */
-+static inline void hci_sched_sco(struct hci_dev *hdev)
- {
-- evt_conn_complete *cc = (evt_conn_complete *) skb->data;
-- struct hci_conn *conn = NULL;
-- struct hci_proto *hp;
--
-- DBG("%s", hdev->name);
--
-- tasklet_disable(&hdev->tx_task);
--
-- if (!cc->status)
-- conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr);
-+ struct hci_conn *conn;
-+ struct sk_buff *skb;
-+ int quote;
-
-- /* Notify upper protocols */
-- if (cc->link_type == ACL_LINK) {
-- /* ACL link notify L2CAP layer */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
-- hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
-- } else {
-- /* SCO link (no notification) */
-- }
-+ BT_DBG("%s", hdev->name);
-
-- tasklet_enable(&hdev->tx_task);
--}
-+ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
-+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-+ BT_DBG("skb %p len %d", skb, skb->len);
-+ hci_send_frame(skb);
-
--/* Disconnect Complete */
--static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
-- struct hci_conn *conn = NULL;
-- struct hci_proto *hp;
-- __u16 handle = __le16_to_cpu(dc->handle);
--
-- DBG("%s", hdev->name);
--
-- if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
-- tasklet_disable(&hdev->tx_task);
--
-- /* Notify upper protocols */
-- if (conn->type == ACL_LINK) {
-- /* ACL link notify L2CAP layer */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
-- hp->disconn_ind(conn, dc->reason);
-- } else {
-- /* SCO link (no notification) */
-+ conn->sent++;
-+ if (conn->sent == ~0)
-+ conn->sent = 0;
- }
--
-- hci_conn_del(hdev, conn);
--
-- tasklet_enable(&hdev->tx_task);
- }
- }
-
--/* Number of completed packets */
--static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static void hci_tx_task(unsigned long arg)
- {
-- evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
-- __u16 *ptr;
-- int i;
--
-- skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
--
-- DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-+ struct hci_dev *hdev = (struct hci_dev *) arg;
-+ struct sk_buff *skb;
-
-- if (skb->len < nc->num_hndl * 4) {
-- DBG("%s bad parameters", hdev->name);
-- return;
-- }
-+ read_lock(&hci_task_lock);
-
-- tasklet_disable(&hdev->tx_task);
-+ BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
-
-- for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
-- struct hci_conn *conn;
-- __u16 handle, count;
-+ /* Schedule queues and send stuff to HCI driver */
-
-- handle = __le16_to_cpu(get_unaligned(ptr++));
-- count = __le16_to_cpu(get_unaligned(ptr++));
-+ hci_sched_acl(hdev);
-
-- hdev->acl_cnt += count;
-+ hci_sched_sco(hdev);
-
-- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
-- conn->sent -= count;
-- }
-+ /* Send next queued raw (unknown type) packet */
-+ while ((skb = skb_dequeue(&hdev->raw_q)))
-+ hci_send_frame(skb);
-
-- tasklet_enable(&hdev->tx_task);
--
-- hci_sched_tx(hdev);
-+ read_unlock(&hci_task_lock);
- }
-
--static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
--{
-- hci_event_hdr *he = (hci_event_hdr *) skb->data;
-- evt_cmd_status *cs;
-- evt_cmd_complete *ec;
-- __u16 opcode, ocf, ogf;
--
-- skb_pull(skb, HCI_EVENT_HDR_SIZE);
--
-- DBG("%s evt 0x%x", hdev->name, he->evt);
--
-- switch (he->evt) {
-- case EVT_NUM_COMP_PKTS:
-- hci_num_comp_pkts_evt(hdev, skb);
-- break;
--
-- case EVT_INQUIRY_COMPLETE:
-- hci_inquiry_complete_evt(hdev, skb);
-- break;
--
-- case EVT_INQUIRY_RESULT:
-- hci_inquiry_result_evt(hdev, skb);
-- break;
--
-- case EVT_CONN_REQUEST:
-- hci_conn_request_evt(hdev, skb);
-- break;
--
-- case EVT_CONN_COMPLETE:
-- hci_conn_complete_evt(hdev, skb);
-- break;
--
-- case EVT_DISCONN_COMPLETE:
-- hci_disconn_complete_evt(hdev, skb);
-- break;
--
-- case EVT_CMD_STATUS:
-- cs = (evt_cmd_status *) skb->data;
-- skb_pull(skb, EVT_CMD_STATUS_SIZE);
--
-- opcode = __le16_to_cpu(cs->opcode);
-- ogf = cmd_opcode_ogf(opcode);
-- ocf = cmd_opcode_ocf(opcode);
--
-- switch (ogf) {
-- case OGF_INFO_PARAM:
-- hci_cs_info_param(hdev, ocf, cs->status);
-- break;
--
-- case OGF_HOST_CTL:
-- hci_cs_host_ctl(hdev, ocf, cs->status);
-- break;
--
-- case OGF_LINK_CTL:
-- hci_cs_link_ctl(hdev, ocf, cs->status);
-- break;
--
-- case OGF_LINK_POLICY:
-- hci_cs_link_policy(hdev, ocf, cs->status);
-- break;
--
-- default:
-- DBG("%s Command Status OGF %x", hdev->name, ogf);
-- break;
-- };
--
-- if (cs->ncmd) {
-- atomic_set(&hdev->cmd_cnt, 1);
-- if (!skb_queue_empty(&hdev->cmd_q))
-- hci_sched_cmd(hdev);
-- }
-- break;
--
-- case EVT_CMD_COMPLETE:
-- ec = (evt_cmd_complete *) skb->data;
-- skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
--
-- opcode = __le16_to_cpu(ec->opcode);
-- ogf = cmd_opcode_ogf(opcode);
-- ocf = cmd_opcode_ocf(opcode);
--
-- switch (ogf) {
-- case OGF_INFO_PARAM:
-- hci_cc_info_param(hdev, ocf, skb);
-- break;
--
-- case OGF_HOST_CTL:
-- hci_cc_host_ctl(hdev, ocf, skb);
-- break;
--
-- case OGF_LINK_CTL:
-- hci_cc_link_ctl(hdev, ocf, skb);
-- break;
--
-- case OGF_LINK_POLICY:
-- hci_cc_link_policy(hdev, ocf, skb);
-- break;
-
-- default:
-- DBG("%s Command Completed OGF %x", hdev->name, ogf);
-- break;
-- };
--
-- if (ec->ncmd) {
-- atomic_set(&hdev->cmd_cnt, 1);
-- if (!skb_queue_empty(&hdev->cmd_q))
-- hci_sched_cmd(hdev);
-- }
-- break;
-- };
--
-- kfree_skb(skb);
-- hdev->stat.evt_rx++;
--}
-+/* ----- HCI RX task (incomming data proccessing) ----- */
-
- /* ACL data packet */
- static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-@@ -1867,51 +1255,86 @@
- flags = acl_flags(handle);
- handle = acl_handle(handle);
-
-- DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-+ BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-+
-+ hdev->stat.acl_rx++;
-
-- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
-+ hci_dev_lock(hdev);
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ hci_dev_unlock(hdev);
-+
-+ if (conn) {
- register struct hci_proto *hp;
-
- /* Send to upper protocol */
-- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) {
-+ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
- hp->recv_acldata(conn, skb, flags);
-- goto sent;
-+ return;
- }
- } else {
-- ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle);
-+ BT_ERR("%s ACL packet for unknown connection handle %d",
-+ hdev->name, handle);
- }
-
- kfree_skb(skb);
--sent:
-- hdev->stat.acl_rx++;
- }
-
- /* SCO data packet */
- static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
- {
-- DBG("%s len %d", hdev->name, skb->len);
-+ hci_sco_hdr *sh = (void *) skb->data;
-+ struct hci_conn *conn;
-+ __u16 handle;
-+
-+ skb_pull(skb, HCI_SCO_HDR_SIZE);
-+
-+ handle = __le16_to_cpu(sh->handle);
-+
-+ BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
-
-- kfree_skb(skb);
- hdev->stat.sco_rx++;
-+
-+ hci_dev_lock(hdev);
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ hci_dev_unlock(hdev);
-+
-+ if (conn) {
-+ register struct hci_proto *hp;
-+
-+ /* Send to upper protocol */
-+ if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
-+ hp->recv_scodata(conn, skb);
-+ return;
-+ }
-+ } else {
-+ BT_ERR("%s SCO packet for unknown connection handle %d",
-+ hdev->name, handle);
-+ }
-+
-+ kfree_skb(skb);
- }
-
--/* ----- HCI tasks ----- */
- void hci_rx_task(unsigned long arg)
- {
- struct hci_dev *hdev = (struct hci_dev *) arg;
- struct sk_buff *skb;
-
-- DBG("%s", hdev->name);
-+ BT_DBG("%s", hdev->name);
-
- read_lock(&hci_task_lock);
-
- while ((skb = skb_dequeue(&hdev->rx_q))) {
-- if (hdev->flags & HCI_SOCK) {
-+ if (atomic_read(&hdev->promisc)) {
- /* Send copy to the sockets */
- hci_send_to_sock(hdev, skb);
- }
-
-- if (hdev->flags & HCI_INIT) {
-+ if (test_bit(HCI_RAW, &hdev->flags)) {
-+ kfree_skb(skb);
-+ continue;
-+ }
-+
-+ if (test_bit(HCI_INIT, &hdev->flags)) {
- /* Don't process data packets in this states. */
- switch (skb->pkt_type) {
- case HCI_ACLDATA_PKT:
-@@ -1921,64 +1344,43 @@
- };
- }
-
-- if (hdev->flags & HCI_NORMAL) {
-- /* Process frame */
-- switch (skb->pkt_type) {
-- case HCI_EVENT_PKT:
-- hci_event_packet(hdev, skb);
-- break;
-+ /* Process frame */
-+ switch (skb->pkt_type) {
-+ case HCI_EVENT_PKT:
-+ hci_event_packet(hdev, skb);
-+ break;
-
-- case HCI_ACLDATA_PKT:
-- DBG("%s ACL data packet", hdev->name);
-- hci_acldata_packet(hdev, skb);
-- break;
-+ case HCI_ACLDATA_PKT:
-+ BT_DBG("%s ACL data packet", hdev->name);
-+ hci_acldata_packet(hdev, skb);
-+ break;
-
-- case HCI_SCODATA_PKT:
-- DBG("%s SCO data packet", hdev->name);
-- hci_scodata_packet(hdev, skb);
-- break;
-+ case HCI_SCODATA_PKT:
-+ BT_DBG("%s SCO data packet", hdev->name);
-+ hci_scodata_packet(hdev, skb);
-+ break;
-
-- default:
-- kfree_skb(skb);
-- break;
-- };
-- } else {
-+ default:
- kfree_skb(skb);
-+ break;
- }
- }
-
- read_unlock(&hci_task_lock);
- }
-
--static void hci_tx_task(unsigned long arg)
--{
-- struct hci_dev *hdev = (struct hci_dev *) arg;
-- struct sk_buff *skb;
--
-- read_lock(&hci_task_lock);
--
-- DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
--
-- /* Schedule queues and send stuff to HCI driver */
--
-- hci_sched_acl(hdev);
--
-- hci_sched_sco(hdev);
--
-- /* Send next queued raw (unknown type) packet */
-- while ((skb = skb_dequeue(&hdev->raw_q)))
-- hci_send_frame(skb);
--
-- read_unlock(&hci_task_lock);
--}
--
- static void hci_cmd_task(unsigned long arg)
- {
- struct hci_dev *hdev = (struct hci_dev *) arg;
- struct sk_buff *skb;
-
-- DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-+ BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-
-+ if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
-+ BT_ERR("%s command tx timeout", hdev->name);
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ }
-+
- /* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
- if (hdev->sent_cmd)
-@@ -1987,6 +1389,7 @@
- if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
- atomic_dec(&hdev->cmd_cnt);
- hci_send_frame(skb);
-+ hdev->cmd_last_tx = jiffies;
- } else {
- skb_queue_head(&hdev->cmd_q, skb);
- hci_sched_cmd(hdev);
-@@ -1994,33 +1397,10 @@
- }
- }
-
--/* Receive frame from HCI drivers */
--int hci_recv_frame(struct sk_buff *skb)
--{
-- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--
-- if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
-- kfree_skb(skb);
-- return -1;
-- }
--
-- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
-- /* Incomming skb */
-- bluez_cb(skb)->incomming = 1;
--
-- /* Queue frame for rx task */
-- skb_queue_tail(&hdev->rx_q, skb);
-- hci_sched_rx(hdev);
--
-- return 0;
--}
-+/* ---- Initialization ---- */
-
- int hci_core_init(void)
- {
-- /* Init locks */
-- spin_lock_init(&hdev_list_lock);
--
- return 0;
- }
-
-@@ -2028,5 +1408,3 @@
- {
- return 0;
- }
--
--MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/hci_event.c linux-2.4.18-mh9/net/bluetooth/hci_event.c
---- linux-2.4.18/net/bluetooth/hci_event.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/hci_event.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,927 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * HCI Events.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/notifier.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef HCI_CORE_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+/* Handle HCI Event packets */
-+
-+/* Command Complete OGF LINK_CTL */
-+static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ __u8 status;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_INQUIRY_CANCEL:
-+ status = *((__u8 *) skb->data);
-+
-+ if (status) {
-+ BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
-+ } else {
-+ clear_bit(HCI_INQUIRY, &hdev->flags);
-+ hci_req_complete(hdev, status);
-+ }
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Complete OGF LINK_POLICY */
-+static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ struct hci_conn *conn;
-+ role_discovery_rp *rd;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_ROLE_DISCOVERY:
-+ rd = (void *) skb->data;
-+
-+ if (rd->status)
-+ break;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
-+ if (conn) {
-+ if (rd->role)
-+ conn->link_mode &= ~HCI_LM_MASTER;
-+ else
-+ conn->link_mode |= HCI_LM_MASTER;
-+ }
-+
-+ hci_dev_unlock(hdev);
-+ break;
-+
-+ default:
-+ BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
-+ hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Complete OGF HOST_CTL */
-+static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ __u8 status, param;
-+ __u16 setting;
-+ read_voice_setting_rp *vs;
-+ void *sent;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_RESET:
-+ status = *((__u8 *) skb->data);
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_SET_EVENT_FLT:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-+ } else {
-+ BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-+ }
-+ break;
-+
-+ case OCF_WRITE_AUTH_ENABLE:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
-+ if (!sent)
-+ break;
-+
-+ status = *((__u8 *) skb->data);
-+ param = *((__u8 *) sent);
-+
-+ if (!status) {
-+ if (param == AUTH_ENABLED)
-+ set_bit(HCI_AUTH, &hdev->flags);
-+ else
-+ clear_bit(HCI_AUTH, &hdev->flags);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_WRITE_ENCRYPT_MODE:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
-+ if (!sent)
-+ break;
-+
-+ status = *((__u8 *) skb->data);
-+ param = *((__u8 *) sent);
-+
-+ if (!status) {
-+ if (param)
-+ set_bit(HCI_ENCRYPT, &hdev->flags);
-+ else
-+ clear_bit(HCI_ENCRYPT, &hdev->flags);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_WRITE_CA_TIMEOUT:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-+ } else {
-+ BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-+ }
-+ break;
-+
-+ case OCF_WRITE_PG_TIMEOUT:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-+ } else {
-+ BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-+ }
-+ break;
-+
-+ case OCF_WRITE_SCAN_ENABLE:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
-+ if (!sent)
-+ break;
-+
-+ status = *((__u8 *) skb->data);
-+ param = *((__u8 *) sent);
-+
-+ BT_DBG("param 0x%x", param);
-+
-+ if (!status) {
-+ clear_bit(HCI_PSCAN, &hdev->flags);
-+ clear_bit(HCI_ISCAN, &hdev->flags);
-+ if (param & SCAN_INQUIRY)
-+ set_bit(HCI_ISCAN, &hdev->flags);
-+
-+ if (param & SCAN_PAGE)
-+ set_bit(HCI_PSCAN, &hdev->flags);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_READ_VOICE_SETTING:
-+ vs = (read_voice_setting_rp *) skb->data;
-+
-+ if (vs->status) {
-+ BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vc->status);
-+ break;
-+ }
-+
-+ setting = __le16_to_cpu(vs->voice_setting);
-+
-+ if (hdev->voice_setting != setting ) {
-+ hdev->voice_setting = setting;
-+
-+ BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
-+
-+ if (hdev->notify)
-+ hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING, 0);
-+ }
-+
-+ break;
-+
-+ case OCF_WRITE_VOICE_SETTING:
-+ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
-+ if (!sent)
-+ break;
-+
-+ status = *((__u8 *) skb->data);
-+ setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
-+
-+ if (!status && hdev->voice_setting != setting) {
-+ hdev->voice_setting = setting;
-+
-+ BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
-+
-+ if (hdev->notify)
-+ hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING, 0);
-+ }
-+ hci_req_complete(hdev, status);
-+ break;
-+
-+ case OCF_HOST_BUFFER_SIZE:
-+ status = *((__u8 *) skb->data);
-+ if (status) {
-+ BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
-+ hci_req_complete(hdev, status);
-+ }
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Complete OGF INFO_PARAM */
-+static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+ read_local_features_rp *lf;
-+ read_buffer_size_rp *bs;
-+ read_bd_addr_rp *ba;
-+
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_READ_LOCAL_FEATURES:
-+ lf = (read_local_features_rp *) skb->data;
-+
-+ if (lf->status) {
-+ BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-+ break;
-+ }
-+
-+ memcpy(hdev->features, lf->features, sizeof(hdev->features));
-+
-+ /* Adjust default settings according to features
-+ * supported by device. */
-+ if (hdev->features[0] & LMP_3SLOT)
-+ hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-+
-+ if (hdev->features[0] & LMP_5SLOT)
-+ hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-+
-+ if (hdev->features[1] & LMP_HV2)
-+ hdev->pkt_type |= (HCI_HV2);
-+
-+ if (hdev->features[1] & LMP_HV3)
-+ hdev->pkt_type |= (HCI_HV3);
-+
-+ BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
-+
-+ break;
-+
-+ case OCF_READ_BUFFER_SIZE:
-+ bs = (read_buffer_size_rp *) skb->data;
-+
-+ if (bs->status) {
-+ BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-+ hci_req_complete(hdev, bs->status);
-+ break;
-+ }
-+
-+ hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
-+ hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64;
-+ hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-+ hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
-+
-+ BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-+ hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
-+
-+ break;
-+
-+ case OCF_READ_BD_ADDR:
-+ ba = (read_bd_addr_rp *) skb->data;
-+
-+ if (!ba->status) {
-+ bacpy(&hdev->bdaddr, &ba->bdaddr);
-+ } else {
-+ BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-+ }
-+
-+ hci_req_complete(hdev, ba->status);
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF LINK_CTL */
-+static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
-+{
-+ struct hci_conn *conn;
-+ create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
-+
-+ if (!cc)
-+ return;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr);
-+
-+ BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
-+ status, batostr(&cc->bdaddr), conn);
-+
-+ if (status) {
-+ if (conn) {
-+ conn->state = BT_CLOSED;
-+ hci_proto_connect_cfm(conn, status);
-+ hci_conn_del(conn);
-+ }
-+ } else {
-+ if (!conn) {
-+ conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr);
-+ if (conn) {
-+ conn->out = 1;
-+ conn->link_mode |= HCI_LM_MASTER;
-+ } else
-+ BT_ERR("No memmory for new connection");
-+ }
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ case OCF_CREATE_CONN:
-+ hci_cs_create_conn(hdev, status);
-+ break;
-+
-+ case OCF_ADD_SCO:
-+ if (status) {
-+ struct hci_conn *acl, *sco;
-+ add_sco_cp *cp = hci_sent_cmd_data(hdev,
-+ OGF_LINK_CTL, OCF_ADD_SCO);
-+ __u16 handle;
-+
-+ if (!cp)
-+ break;
-+
-+ handle = __le16_to_cpu(cp->handle);
-+
-+ BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
-+
-+ hci_dev_lock(hdev);
-+
-+ acl = conn_hash_lookup_handle(hdev, handle);
-+ if (acl && (sco = acl->link)) {
-+ sco->state = BT_CLOSED;
-+ hci_proto_connect_cfm(sco, status);
-+ hci_conn_del(sco);
-+ }
-+
-+ hci_dev_unlock(hdev);
-+ }
-+ break;
-+
-+ case OCF_INQUIRY:
-+ if (status) {
-+ BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-+ hci_req_complete(hdev, status);
-+ } else {
-+ set_bit(HCI_INQUIRY, &hdev->flags);
-+ }
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d",
-+ hdev->name, ocf, status);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF LINK_POLICY */
-+static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ default:
-+ BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF HOST_CTL */
-+static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ default:
-+ BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Command Status OGF INFO_PARAM */
-+static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+ BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
-+
-+ switch (ocf) {
-+ default:
-+ BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-+ break;
-+ };
-+}
-+
-+/* Inquiry Complete */
-+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ __u8 status = *((__u8 *) skb->data);
-+
-+ BT_DBG("%s status %d", hdev->name, status);
-+
-+ clear_bit(HCI_INQUIRY, &hdev->flags);
-+ hci_req_complete(hdev, status);
-+}
-+
-+/* Inquiry Result */
-+static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ inquiry_info *info = (inquiry_info *) (skb->data + 1);
-+ int num_rsp = *((__u8 *) skb->data);
-+
-+ BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-+
-+ hci_dev_lock(hdev);
-+ for (; num_rsp; num_rsp--)
-+ inquiry_cache_update(hdev, info++);
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Connect Request */
-+static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_conn_request *cr = (evt_conn_request *) skb->data;
-+ int mask = hdev->link_mode;
-+
-+ BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
-+ batostr(&cr->bdaddr), cr->link_type);
-+
-+ mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type);
-+
-+ if (mask & HCI_LM_ACCEPT) {
-+ /* Connection accepted */
-+ struct hci_conn *conn;
-+ accept_conn_req_cp ac;
-+
-+ hci_dev_lock(hdev);
-+ conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr);
-+ if (!conn) {
-+ if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) {
-+ BT_ERR("No memmory for new connection");
-+ hci_dev_unlock(hdev);
-+ return;
-+ }
-+ }
-+ conn->state = BT_CONNECT;
-+ hci_dev_unlock(hdev);
-+
-+ bacpy(&ac.bdaddr, &cr->bdaddr);
-+
-+ if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
-+ ac.role = 0x00; /* Become master */
-+ else
-+ ac.role = 0x01; /* Remain slave */
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ,
-+ ACCEPT_CONN_REQ_CP_SIZE, &ac);
-+ } else {
-+ /* Connection rejected */
-+ reject_conn_req_cp rc;
-+
-+ bacpy(&rc.bdaddr, &cr->bdaddr);
-+ rc.reason = 0x0f;
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ,
-+ REJECT_CONN_REQ_CP_SIZE, &rc);
-+ }
-+}
-+
-+/* Connect Complete */
-+static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_conn_complete *cc = (evt_conn_complete *) skb->data;
-+ struct hci_conn *conn = NULL;
-+
-+ BT_DBG("%s", hdev->name);
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
-+ if (!conn) {
-+ hci_dev_unlock(hdev);
-+ return;
-+ }
-+
-+ if (!cc->status) {
-+ conn->handle = __le16_to_cpu(cc->handle);
-+ conn->state = BT_CONNECTED;
-+
-+ if (test_bit(HCI_AUTH, &hdev->flags))
-+ conn->link_mode |= HCI_LM_AUTH;
-+
-+ if (test_bit(HCI_ENCRYPT, &hdev->flags))
-+ conn->link_mode |= HCI_LM_ENCRYPT;
-+
-+
-+ /* Set link policy */
-+ if (conn->type == ACL_LINK && hdev->link_policy) {
-+ write_link_policy_cp lp;
-+ lp.handle = cc->handle;
-+ lp.policy = __cpu_to_le16(hdev->link_policy);
-+ hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
-+ WRITE_LINK_POLICY_CP_SIZE, &lp);
-+ }
-+
-+ /* Set packet type for incomming connection */
-+ if (!conn->out) {
-+ change_conn_ptype_cp cp;
-+ cp.handle = cc->handle;
-+ cp.pkt_type = (conn->type == ACL_LINK) ?
-+ __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
-+ __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-+
-+ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE,
-+ CHANGE_CONN_PTYPE_CP_SIZE, &cp);
-+ }
-+ } else
-+ conn->state = BT_CLOSED;
-+
-+ if (conn->type == ACL_LINK) {
-+ struct hci_conn *sco = conn->link;
-+ if (sco) {
-+ if (!cc->status)
-+ hci_add_sco(sco, conn->handle);
-+ else {
-+ hci_proto_connect_cfm(sco, cc->status);
-+ hci_conn_del(sco);
-+ }
-+ }
-+ }
-+
-+ hci_proto_connect_cfm(conn, cc->status);
-+ if (cc->status)
-+ hci_conn_del(conn);
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Disconnect Complete */
-+static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
-+ struct hci_conn *conn = NULL;
-+ __u16 handle = __le16_to_cpu(dc->handle);
-+
-+ BT_DBG("%s status %d", hdev->name, dc->status);
-+
-+ if (dc->status)
-+ return;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ conn->state = BT_CLOSED;
-+ hci_proto_disconn_ind(conn, dc->reason);
-+ hci_conn_del(conn);
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Number of completed packets */
-+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
-+ __u16 *ptr;
-+ int i;
-+
-+ skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
-+
-+ BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-+
-+ if (skb->len < nc->num_hndl * 4) {
-+ BT_DBG("%s bad parameters", hdev->name);
-+ return;
-+ }
-+
-+ tasklet_disable(&hdev->tx_task);
-+
-+ for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
-+ struct hci_conn *conn;
-+ __u16 handle, count;
-+
-+ handle = __le16_to_cpu(get_unaligned(ptr++));
-+ count = __le16_to_cpu(get_unaligned(ptr++));
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ conn->sent -= count;
-+
-+ if (conn->type == SCO_LINK) {
-+ if ((hdev->sco_cnt += count) > hdev->sco_pkts)
-+ hdev->sco_cnt = hdev->sco_pkts;
-+ } else {
-+ if ((hdev->acl_cnt += count) > hdev->acl_pkts)
-+ hdev->acl_cnt = hdev->acl_pkts;
-+ }
-+ }
-+ }
-+ hci_sched_tx(hdev);
-+
-+ tasklet_enable(&hdev->tx_task);
-+}
-+
-+/* Role Change */
-+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_role_change *rc = (evt_role_change *) skb->data;
-+ struct hci_conn *conn = NULL;
-+
-+ BT_DBG("%s status %d", hdev->name, rc->status);
-+
-+ if (rc->status)
-+ return;
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
-+ if (conn) {
-+ if (rc->role)
-+ conn->link_mode &= ~HCI_LM_MASTER;
-+ else
-+ conn->link_mode |= HCI_LM_MASTER;
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Authentication Complete */
-+static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_auth_complete *ac = (evt_auth_complete *) skb->data;
-+ struct hci_conn *conn = NULL;
-+ __u16 handle = __le16_to_cpu(ac->handle);
-+
-+ BT_DBG("%s status %d", hdev->name, ac->status);
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ if (!ac->status)
-+ conn->link_mode |= HCI_LM_AUTH;
-+ clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-+
-+ hci_proto_auth_cfm(conn, ac->status);
-+
-+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
-+ if (!ac->status) {
-+ set_conn_encrypt_cp ce;
-+ ce.handle = __cpu_to_le16(conn->handle);
-+ ce.encrypt = 1;
-+ hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-+ OCF_SET_CONN_ENCRYPT,
-+ SET_CONN_ENCRYPT_CP_SIZE, &ce);
-+ } else {
-+ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-+ hci_proto_encrypt_cfm(conn, ac->status);
-+ }
-+ }
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+/* Encryption Change */
-+static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ evt_encrypt_change *ec = (evt_encrypt_change *) skb->data;
-+ struct hci_conn *conn = NULL;
-+ __u16 handle = __le16_to_cpu(ec->handle);
-+
-+ BT_DBG("%s status %d", hdev->name, ec->status);
-+
-+ hci_dev_lock(hdev);
-+
-+ conn = conn_hash_lookup_handle(hdev, handle);
-+ if (conn) {
-+ if (!ec->status) {
-+ if (ec->encrypt)
-+ conn->link_mode |= HCI_LM_ENCRYPT;
-+ else
-+ conn->link_mode &= ~HCI_LM_ENCRYPT;
-+ }
-+ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-+
-+ hci_proto_encrypt_cfm(conn, ec->status);
-+ }
-+
-+ hci_dev_unlock(hdev);
-+}
-+
-+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+ hci_event_hdr *he = (hci_event_hdr *) skb->data;
-+ evt_cmd_status *cs;
-+ evt_cmd_complete *ec;
-+ __u16 opcode, ocf, ogf;
-+
-+ skb_pull(skb, HCI_EVENT_HDR_SIZE);
-+
-+ BT_DBG("%s evt 0x%x", hdev->name, he->evt);
-+
-+ switch (he->evt) {
-+ case EVT_NUM_COMP_PKTS:
-+ hci_num_comp_pkts_evt(hdev, skb);
-+ break;
-+
-+ case EVT_INQUIRY_COMPLETE:
-+ hci_inquiry_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_INQUIRY_RESULT:
-+ hci_inquiry_result_evt(hdev, skb);
-+ break;
-+
-+ case EVT_CONN_REQUEST:
-+ hci_conn_request_evt(hdev, skb);
-+ break;
-+
-+ case EVT_CONN_COMPLETE:
-+ hci_conn_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_DISCONN_COMPLETE:
-+ hci_disconn_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_ROLE_CHANGE:
-+ hci_role_change_evt(hdev, skb);
-+ break;
-+
-+ case EVT_AUTH_COMPLETE:
-+ hci_auth_complete_evt(hdev, skb);
-+ break;
-+
-+ case EVT_ENCRYPT_CHANGE:
-+ hci_encrypt_change_evt(hdev, skb);
-+ break;
-+
-+ case EVT_CMD_STATUS:
-+ cs = (evt_cmd_status *) skb->data;
-+ skb_pull(skb, EVT_CMD_STATUS_SIZE);
-+
-+ opcode = __le16_to_cpu(cs->opcode);
-+ ogf = cmd_opcode_ogf(opcode);
-+ ocf = cmd_opcode_ocf(opcode);
-+
-+ switch (ogf) {
-+ case OGF_INFO_PARAM:
-+ hci_cs_info_param(hdev, ocf, cs->status);
-+ break;
-+
-+ case OGF_HOST_CTL:
-+ hci_cs_host_ctl(hdev, ocf, cs->status);
-+ break;
-+
-+ case OGF_LINK_CTL:
-+ hci_cs_link_ctl(hdev, ocf, cs->status);
-+ break;
-+
-+ case OGF_LINK_POLICY:
-+ hci_cs_link_policy(hdev, ocf, cs->status);
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
-+ break;
-+ };
-+
-+ if (cs->ncmd) {
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ if (!skb_queue_empty(&hdev->cmd_q))
-+ hci_sched_cmd(hdev);
-+ }
-+ break;
-+
-+ case EVT_CMD_COMPLETE:
-+ ec = (evt_cmd_complete *) skb->data;
-+ skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
-+
-+ opcode = __le16_to_cpu(ec->opcode);
-+ ogf = cmd_opcode_ogf(opcode);
-+ ocf = cmd_opcode_ocf(opcode);
-+
-+ switch (ogf) {
-+ case OGF_INFO_PARAM:
-+ hci_cc_info_param(hdev, ocf, skb);
-+ break;
-+
-+ case OGF_HOST_CTL:
-+ hci_cc_host_ctl(hdev, ocf, skb);
-+ break;
-+
-+ case OGF_LINK_CTL:
-+ hci_cc_link_ctl(hdev, ocf, skb);
-+ break;
-+
-+ case OGF_LINK_POLICY:
-+ hci_cc_link_policy(hdev, ocf, skb);
-+ break;
-+
-+ default:
-+ BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
-+ break;
-+ };
-+
-+ if (ec->ncmd) {
-+ atomic_set(&hdev->cmd_cnt, 1);
-+ if (!skb_queue_empty(&hdev->cmd_q))
-+ hci_sched_cmd(hdev);
-+ }
-+ break;
-+ };
-+
-+ kfree_skb(skb);
-+ hdev->stat.evt_rx++;
-+}
-+
-+/* General internal stack event */
-+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-+{
-+ hci_event_hdr *eh;
-+ evt_stack_internal *si;
-+ struct sk_buff *skb;
-+ int size;
-+ void *ptr;
-+
-+ size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
-+ skb = bluez_skb_alloc(size, GFP_ATOMIC);
-+ if (!skb)
-+ return;
-+
-+ ptr = skb_put(skb, size);
-+
-+ eh = ptr;
-+ eh->evt = EVT_STACK_INTERNAL;
-+ eh->plen = EVT_STACK_INTERNAL_SIZE + dlen;
-+ ptr += HCI_EVENT_HDR_SIZE;
-+
-+ si = ptr;
-+ si->type = type;
-+ memcpy(si->data, data, dlen);
-+
-+ skb->pkt_type = HCI_EVENT_PKT;
-+ skb->dev = (void *) hdev;
-+ hci_send_to_sock(hdev, skb);
-+ kfree_skb(skb);
-+}
-diff -urN linux-2.4.18/net/bluetooth/hci_sock.c linux-2.4.18-mh9/net/bluetooth/hci_sock.c
---- linux-2.4.18/net/bluetooth/hci_sock.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/net/bluetooth/hci_sock.c Mon Aug 25 18:38:12 2003
-@@ -25,7 +25,7 @@
- /*
- * BlueZ HCI socket layer.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
-@@ -49,45 +49,54 @@
-
- #include <asm/system.h>
- #include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
-
- #ifndef HCI_SOCK_DEBUG
--#undef DBG
--#define DBG( A... )
-+#undef BT_DBG
-+#define BT_DBG( A... )
- #endif
-
--/* HCI socket interface */
-+/* ----- HCI socket interface ----- */
-+
-+/* Security filter */
-+static struct hci_sec_filter hci_sec_filter = {
-+ /* Packet types */
-+ 0x10,
-+ /* Events */
-+ { 0xd9fe, 0x0 },
-+ /* Commands */
-+ {
-+ { 0x0 },
-+ /* OGF_LINK_CTL */
-+ { 0x2a000002, 0x0, 0x0, 0x0 },
-+ /* OGF_LINK_POLICY */
-+ { 0x1200, 0x0, 0x0, 0x0 },
-+ /* OGF_HOST_CTL */
-+ { 0x80100000, 0x202a, 0x0, 0x0 },
-+ /* OGF_INFO_PARAM */
-+ { 0x22a, 0x0, 0x0, 0x0 },
-+ /* OGF_STATUS_PARAM */
-+ { 0x2e, 0x0, 0x0, 0x0 }
-+ }
-+};
-
- static struct bluez_sock_list hci_sk_list = {
- lock: RW_LOCK_UNLOCKED
- };
-
--static struct sock *hci_sock_lookup(struct hci_dev *hdev)
--{
-- struct sock *sk;
--
-- read_lock(&hci_sk_list.lock);
-- for (sk = hci_sk_list.head; sk; sk = sk->next) {
-- if (hci_pi(sk)->hdev == hdev)
-- break;
-- }
-- read_unlock(&hci_sk_list.lock);
-- return sk;
--}
--
- /* Send frame to RAW socket */
- void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct sock * sk;
-
-- DBG("hdev %p len %d", hdev, skb->len);
-+ BT_DBG("hdev %p len %d", hdev, skb->len);
-
- read_lock(&hci_sk_list.lock);
- for (sk = hci_sk_list.head; sk; sk = sk->next) {
-- struct hci_filter *flt;
-+ struct hci_filter *flt;
- struct sk_buff *nskb;
-
- if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
-@@ -100,13 +109,19 @@
- /* Apply filter */
- flt = &hci_pi(sk)->filter;
-
-- if (!test_bit(skb->pkt_type, &flt->type_mask))
-+ if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
- continue;
-
- if (skb->pkt_type == HCI_EVENT_PKT) {
-- register int evt = (*(__u8 *)skb->data & 63);
-+ register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
-+
-+ if (!hci_test_bit(evt, &flt->event_mask))
-+ continue;
-
-- if (!test_bit(evt, &flt->event_mask))
-+ if (flt->opcode && ((evt == EVT_CMD_COMPLETE &&
-+ flt->opcode != *(__u16 *)(skb->data + 3)) ||
-+ (evt == EVT_CMD_STATUS &&
-+ flt->opcode != *(__u16 *)(skb->data + 4))))
- continue;
- }
-
-@@ -116,8 +131,8 @@
- /* Put type byte before the data */
- memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
-
-- skb_queue_tail(&sk->receive_queue, nskb);
-- sk->data_ready(sk, nskb->len);
-+ if (sock_queue_rcv_skb(sk, nskb))
-+ kfree_skb(nskb);
- }
- read_unlock(&hci_sk_list.lock);
- }
-@@ -127,7 +142,7 @@
- struct sock *sk = sock->sk;
- struct hci_dev *hdev = hci_pi(sk)->hdev;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-@@ -135,9 +150,7 @@
- bluez_sock_unlink(&hci_sk_list, sk);
-
- if (hdev) {
-- if (!hci_sock_lookup(hdev))
-- hdev->flags &= ~HCI_SOCK;
--
-+ atomic_dec(&hdev->promisc);
- hci_dev_put(hdev);
- }
-
-@@ -149,24 +162,55 @@
- sock_put(sk);
-
- MOD_DEC_USE_COUNT;
--
- return 0;
- }
-
--static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+/* Ioctls that require bound socket */
-+static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
- {
-- struct sock *sk = sock->sk;
- struct hci_dev *hdev = hci_pi(sk)->hdev;
-- __u32 mode;
-
-- DBG("cmd %x arg %lx", cmd, arg);
-+ if (!hdev)
-+ return -EBADFD;
-
- switch (cmd) {
-- case HCIGETINFO:
-- return hci_dev_info(arg);
-+ case HCISETRAW:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EACCES;
-
-+ if (arg)
-+ set_bit(HCI_RAW, &hdev->flags);
-+ else
-+ clear_bit(HCI_RAW, &hdev->flags);
-+
-+ return 0;
-+
-+ case HCIGETCONNINFO:
-+ return hci_get_conn_info(hdev, arg);
-+
-+ default:
-+ if (hdev->ioctl)
-+ return hdev->ioctl(hdev, cmd, arg);
-+ return -EINVAL;
-+ }
-+}
-+
-+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct sock *sk = sock->sk;
-+ int err;
-+
-+ BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+ switch (cmd) {
- case HCIGETDEVLIST:
-- return hci_dev_list(arg);
-+ return hci_get_dev_list(arg);
-+
-+ case HCIGETDEVINFO:
-+ return hci_get_dev_info(arg);
-+
-+ case HCIGETCONNLIST:
-+ return hci_get_conn_list(arg);
-
- case HCIDEVUP:
- if (!capable(CAP_NET_ADMIN))
-@@ -183,48 +227,31 @@
- return -EACCES;
- return hci_dev_reset(arg);
-
-- case HCIRESETSTAT:
-+ case HCIDEVRESTAT:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_reset_stat(arg);
-
- case HCISETSCAN:
-- if (!capable(CAP_NET_ADMIN))
-- return -EACCES;
-- return hci_dev_setscan(arg);
--
- case HCISETAUTH:
-- if (!capable(CAP_NET_ADMIN))
-- return -EACCES;
-- return hci_dev_setauth(arg);
--
-- case HCISETRAW:
-- if (!capable(CAP_NET_ADMIN))
-- return -EACCES;
--
-- if (!hdev)
-- return -EBADFD;
--
-- if (arg)
-- mode = HCI_RAW;
-- else
-- mode = HCI_NORMAL;
--
-- return hci_dev_setmode(hdev, mode);
--
-+ case HCISETENCRYPT:
- case HCISETPTYPE:
-+ case HCISETLINKPOL:
-+ case HCISETLINKMODE:
-+ case HCISETACLMTU:
-+ case HCISETSCOMTU:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-- return hci_dev_setptype(arg);
-+ return hci_dev_cmd(cmd, arg);
-
- case HCIINQUIRY:
- return hci_inquiry(arg);
-
-- case HCIGETCONNLIST:
-- return hci_conn_list(arg);
--
- default:
-- return -EINVAL;
-+ lock_sock(sk);
-+ err = hci_sock_bound_ioctl(sk, cmd, arg);
-+ release_sock(sk);
-+ return err;
- };
- }
-
-@@ -233,28 +260,35 @@
- struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
- struct sock *sk = sock->sk;
- struct hci_dev *hdev = NULL;
-+ int err = 0;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p sk %p", sock, sk);
-
- if (!haddr || haddr->hci_family != AF_BLUETOOTH)
- return -EINVAL;
-
-+ lock_sock(sk);
-+
- if (hci_pi(sk)->hdev) {
-- /* Already bound */
-- return 0;
-+ err = -EALREADY;
-+ goto done;
- }
-
- if (haddr->hci_dev != HCI_DEV_NONE) {
-- if (!(hdev = hci_dev_get(haddr->hci_dev)))
-- return -ENODEV;
-+ if (!(hdev = hci_dev_get(haddr->hci_dev))) {
-+ err = -ENODEV;
-+ goto done;
-+ }
-
-- hdev->flags |= HCI_SOCK;
-+ atomic_inc(&hdev->promisc);
- }
-
- hci_pi(sk)->hdev = hdev;
- sk->state = BT_BOUND;
-
-- return 0;
-+done:
-+ release_sock(sk);
-+ return err;
- }
-
- static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
-@@ -262,73 +296,44 @@
- struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
- struct sock *sk = sock->sk;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ lock_sock(sk);
-
- *addr_len = sizeof(*haddr);
- haddr->hci_family = AF_BLUETOOTH;
- haddr->hci_dev = hci_pi(sk)->hdev->id;
-
-+ release_sock(sk);
- return 0;
- }
-
--static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-- struct scm_cookie *scm)
--{
-- struct sock *sk = sock->sk;
-- struct hci_dev *hdev = hci_pi(sk)->hdev;
-- struct sk_buff *skb;
-- int err;
--
-- DBG("sock %p sk %p", sock, sk);
--
-- if (msg->msg_flags & MSG_OOB)
-- return -EOPNOTSUPP;
--
-- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
-- return -EINVAL;
--
-- if (!hdev)
-- return -EBADFD;
--
-- if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
-- return err;
--
-- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
-- kfree_skb(skb);
-- return -EFAULT;
-- }
--
-- skb->dev = (void *) hdev;
-- skb->pkt_type = *((unsigned char *) skb->data);
-- skb_pull(skb, 1);
--
-- /* Send frame to HCI core */
-- hci_send_raw(skb);
--
-- return len;
--}
--
- static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
- {
- __u32 mask = hci_pi(sk)->cmsg_mask;
-
- if (mask & HCI_CMSG_DIR)
- put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
-+
-+ if (mask & HCI_CMSG_TSTAMP)
-+ put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
- }
-
--static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
-- int flags, struct scm_cookie *scm)
-+static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
- {
- int noblock = flags & MSG_DONTWAIT;
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- int copied, err;
-
-- DBG("sock %p sk %p", sock, sk);
-+ BT_DBG("sock %p, sk %p", sock, sk);
-
-- if (flags & (MSG_OOB | MSG_PEEK))
-+ if (flags & (MSG_OOB))
- return -EOPNOTSUPP;
-
-+ if (sk->state == BT_CLOSED)
-+ return 0;
-+
- if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
- return err;
-
-@@ -343,28 +348,107 @@
- skb->h.raw = skb->data;
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-
-- if (hci_pi(sk)->cmsg_mask)
-- hci_sock_cmsg(sk, msg, skb);
--
-+ hci_sock_cmsg(sk, msg, skb);
-+
- skb_free_datagram(sk, skb);
-
- return err ? : copied;
- }
-
-+static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-+ struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ struct hci_dev *hdev;
-+ struct sk_buff *skb;
-+ int err;
-+
-+ BT_DBG("sock %p sk %p", sock, sk);
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
-+ return -EINVAL;
-+
-+ if (len < 4)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (!(hdev = hci_pi(sk)->hdev)) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
-+ goto done;
-+
-+ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
-+ err = -EFAULT;
-+ goto drop;
-+ }
-+
-+ skb->pkt_type = *((unsigned char *) skb->data);
-+ skb_pull(skb, 1);
-+ skb->dev = (void *) hdev;
-+
-+ if (skb->pkt_type == HCI_COMMAND_PKT) {
-+ u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
-+ u16 ogf = cmd_opcode_ogf(opcode);
-+ u16 ocf = cmd_opcode_ocf(opcode);
-+
-+ if (((ogf > HCI_SFLT_MAX_OGF) ||
-+ !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-+ !capable(CAP_NET_RAW)) {
-+ err = -EPERM;
-+ goto drop;
-+ }
-+
-+ if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
-+ skb_queue_tail(&hdev->raw_q, skb);
-+ hci_sched_tx(hdev);
-+ } else {
-+ skb_queue_tail(&hdev->cmd_q, skb);
-+ hci_sched_cmd(hdev);
-+ }
-+ } else {
-+ if (!capable(CAP_NET_RAW)) {
-+ err = -EPERM;
-+ goto drop;
-+ }
-+
-+ skb_queue_tail(&hdev->raw_q, skb);
-+ hci_sched_tx(hdev);
-+ }
-+
-+ err = len;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+
-+drop:
-+ kfree_skb(skb);
-+ goto done;
-+}
-+
- int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
- {
- struct sock *sk = sock->sk;
-- struct hci_filter flt;
-+ struct hci_filter flt = { opcode: 0 };
- int err = 0, opt = 0;
-
-- DBG("sk %p, opt %d", sk, optname);
-+ BT_DBG("sk %p, opt %d", sk, optname);
-
- lock_sock(sk);
-
- switch (optname) {
- case HCI_DATA_DIR:
-- if (get_user(opt, (int *)optval))
-- return -EFAULT;
-+ if (get_user(opt, (int *)optval)) {
-+ err = -EFAULT;
-+ break;
-+ }
-
- if (opt)
- hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
-@@ -372,12 +456,31 @@
- hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
- break;
-
-+ case HCI_TIME_STAMP:
-+ if (get_user(opt, (int *)optval)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ if (opt)
-+ hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
-+ else
-+ hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
-+ break;
-+
- case HCI_FILTER:
- len = MIN(len, sizeof(struct hci_filter));
- if (copy_from_user(&flt, optval, len)) {
- err = -EFAULT;
- break;
- }
-+
-+ if (!capable(CAP_NET_RAW)) {
-+ flt.type_mask &= hci_sec_filter.type_mask;
-+ flt.event_mask[0] &= hci_sec_filter.event_mask[0];
-+ flt.event_mask[1] &= hci_sec_filter.event_mask[1];
-+ }
-+
- memcpy(&hci_pi(sk)->filter, &flt, len);
- break;
-
-@@ -409,6 +512,16 @@
- return -EFAULT;
- break;
-
-+ case HCI_TIME_STAMP:
-+ if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
-+ opt = 1;
-+ else
-+ opt = 0;
-+
-+ if (put_user(opt, optval))
-+ return -EFAULT;
-+ break;
-+
- case HCI_FILTER:
- len = MIN(len, sizeof(struct hci_filter));
- if (copy_to_user(optval, &hci_pi(sk)->filter, len))
-@@ -446,7 +559,7 @@
- {
- struct sock *sk;
-
-- DBG("sock %p", sock);
-+ BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-@@ -464,44 +577,31 @@
- sk->protocol = protocol;
- sk->state = BT_OPEN;
-
-- /* Initialize filter */
-- hci_pi(sk)->filter.type_mask = (1<<HCI_EVENT_PKT);
-- hci_pi(sk)->filter.event_mask[0] = ~0L;
-- hci_pi(sk)->filter.event_mask[1] = ~0L;
--
- bluez_sock_link(&hci_sk_list, sk);
-
- MOD_INC_USE_COUNT;
--
- return 0;
- }
-
- static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
- {
- struct hci_dev *hdev = (struct hci_dev *) ptr;
-- struct sk_buff *skb;
--
-- DBG("hdev %s event %ld", hdev->name, event);
-+ evt_si_device sd;
-+
-+ BT_DBG("hdev %s event %ld", hdev->name, event);
-
- /* Send event to sockets */
-- if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
-- hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
-- evt_hci_dev_event he = { event, hdev->id };
--
-- skb->pkt_type = HCI_EVENT_PKT;
-- memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
-- memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
--
-- hci_send_to_sock(NULL, skb);
-- kfree_skb(skb);
-- }
--
-+ sd.event = event;
-+ sd.dev_id = hdev->id;
-+ hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd);
-+
- if (event == HCI_DEV_UNREG) {
- struct sock *sk;
-
- /* Detach sockets from device */
- read_lock(&hci_sk_list.lock);
- for (sk = hci_sk_list.head; sk; sk = sk->next) {
-+ bh_lock_sock(sk);
- if (hci_pi(sk)->hdev == hdev) {
- hci_pi(sk)->hdev = NULL;
- sk->err = EPIPE;
-@@ -510,6 +610,7 @@
-
- hci_dev_put(hdev);
- }
-+ bh_unlock_sock(sk);
- }
- read_unlock(&hci_sk_list.lock);
- }
-@@ -529,21 +630,19 @@
- int hci_sock_init(void)
- {
- if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
-- ERR("Can't register HCI socket");
-+ BT_ERR("Can't register HCI socket");
- return -EPROTO;
- }
-
- hci_register_notifier(&hci_sock_nblock);
--
- return 0;
- }
-
- int hci_sock_cleanup(void)
- {
- if (bluez_sock_unregister(BTPROTO_HCI))
-- ERR("Can't unregister HCI socket");
-+ BT_ERR("Can't unregister HCI socket");
-
- hci_unregister_notifier(&hci_sock_nblock);
--
- return 0;
- }
-diff -urN linux-2.4.18/net/bluetooth/l2cap.c linux-2.4.18-mh9/net/bluetooth/l2cap.c
---- linux-2.4.18/net/bluetooth/l2cap.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/l2cap.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,2187 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ L2CAP core and sockets.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "2.3"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#ifndef L2CAP_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static struct proto_ops l2cap_sock_ops;
-+
-+struct bluez_sock_list l2cap_sk_list = {
-+ lock: RW_LOCK_UNLOCKED
-+};
-+
-+static int l2cap_conn_del(struct hci_conn *conn, int err);
-+
-+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
-+static void l2cap_chan_del(struct sock *sk, int err);
-+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
-+
-+static void __l2cap_sock_close(struct sock *sk, int reason);
-+static void l2cap_sock_close(struct sock *sk);
-+static void l2cap_sock_kill(struct sock *sk);
-+
-+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
-+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
-+
-+/* ----- L2CAP timers ------ */
-+static void l2cap_sock_timeout(unsigned long arg)
-+{
-+ struct sock *sk = (struct sock *) arg;
-+
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ bh_lock_sock(sk);
-+ __l2cap_sock_close(sk, ETIMEDOUT);
-+ bh_unlock_sock(sk);
-+
-+ l2cap_sock_kill(sk);
-+ sock_put(sk);
-+}
-+
-+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
-+{
-+ BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout);
-+
-+ if (!mod_timer(&sk->timer, jiffies + timeout))
-+ sock_hold(sk);
-+}
-+
-+static void l2cap_sock_clear_timer(struct sock *sk)
-+{
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-+ __sock_put(sk);
-+}
-+
-+static void l2cap_sock_init_timer(struct sock *sk)
-+{
-+ init_timer(&sk->timer);
-+ sk->timer.function = l2cap_sock_timeout;
-+ sk->timer.data = (unsigned long)sk;
-+}
-+
-+/* -------- L2CAP connections --------- */
-+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status)
-+{
-+ struct l2cap_conn *conn;
-+
-+ if ((conn = hcon->l2cap_data))
-+ return conn;
-+
-+ if (status)
-+ return conn;
-+
-+ if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
-+ return NULL;
-+ memset(conn, 0, sizeof(struct l2cap_conn));
-+
-+ hcon->l2cap_data = conn;
-+ conn->hcon = hcon;
-+
-+ conn->mtu = hcon->hdev->acl_mtu;
-+ conn->src = &hcon->hdev->bdaddr;
-+ conn->dst = &hcon->dst;
-+
-+ spin_lock_init(&conn->lock);
-+ conn->chan_list.lock = RW_LOCK_UNLOCKED;
-+
-+ BT_DBG("hcon %p conn %p", hcon, conn);
-+
-+ MOD_INC_USE_COUNT;
-+ return conn;
-+}
-+
-+static int l2cap_conn_del(struct hci_conn *hcon, int err)
-+{
-+ struct l2cap_conn *conn;
-+ struct sock *sk;
-+
-+ if (!(conn = hcon->l2cap_data))
-+ return 0;
-+
-+ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-+
-+ if (conn->rx_skb)
-+ kfree_skb(conn->rx_skb);
-+
-+ /* Kill channels */
-+ while ((sk = conn->chan_list.head)) {
-+ bh_lock_sock(sk);
-+ l2cap_chan_del(sk, err);
-+ bh_unlock_sock(sk);
-+ l2cap_sock_kill(sk);
-+ }
-+
-+ hcon->l2cap_data = NULL;
-+ kfree(conn);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+/* -------- Socket interface ---------- */
-+static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
-+{
-+ struct sock *sk;
-+ for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+ if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+ }
-+ return sk;
-+}
-+
-+/* Find socket with psm and source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
-+{
-+ struct sock *sk, *sk1 = NULL;
-+
-+ for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+ if (state && sk->state != state)
-+ continue;
-+
-+ if (l2cap_pi(sk)->psm == psm) {
-+ /* Exact match. */
-+ if (!bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+
-+ /* Closest match */
-+ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ sk1 = sk;
-+ }
-+ }
-+ return sk ? sk : sk1;
-+}
-+
-+/* Find socket with given address (psm, src).
-+ * Returns locked socket */
-+static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
-+{
-+ struct sock *s;
-+ read_lock(&l2cap_sk_list.lock);
-+ s = __l2cap_get_sock_by_psm(state, psm, src);
-+ if (s) bh_lock_sock(s);
-+ read_unlock(&l2cap_sk_list.lock);
-+ return s;
-+}
-+
-+static void l2cap_sock_destruct(struct sock *sk)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ skb_queue_purge(&sk->receive_queue);
-+ skb_queue_purge(&sk->write_queue);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void l2cap_sock_cleanup_listen(struct sock *parent)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ /* Close not yet accepted channels */
-+ while ((sk = bluez_accept_dequeue(parent, NULL)))
-+ l2cap_sock_close(sk);
-+
-+ parent->state = BT_CLOSED;
-+ parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void l2cap_sock_kill(struct sock *sk)
-+{
-+ if (!sk->zapped || sk->socket)
-+ return;
-+
-+ BT_DBG("sk %p state %d", sk, sk->state);
-+
-+ /* Kill poor orphan */
-+ bluez_sock_unlink(&l2cap_sk_list, sk);
-+ sk->dead = 1;
-+ sock_put(sk);
-+}
-+
-+/* Close socket.
-+ */
-+static void __l2cap_sock_close(struct sock *sk, int reason)
-+{
-+ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-+
-+ switch (sk->state) {
-+ case BT_LISTEN:
-+ l2cap_sock_cleanup_listen(sk);
-+ break;
-+
-+ case BT_CONNECTED:
-+ case BT_CONFIG:
-+ case BT_CONNECT2:
-+ if (sk->type == SOCK_SEQPACKET) {
-+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+ l2cap_disconn_req req;
-+
-+ sk->state = BT_DISCONN;
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+ } else {
-+ l2cap_chan_del(sk, reason);
-+ }
-+ break;
-+
-+ case BT_CONNECT:
-+ case BT_DISCONN:
-+ l2cap_chan_del(sk, reason);
-+ break;
-+
-+ default:
-+ sk->zapped = 1;
-+ break;
-+ };
-+}
-+
-+/* Must be called on unlocked socket. */
-+static void l2cap_sock_close(struct sock *sk)
-+{
-+ l2cap_sock_clear_timer(sk);
-+ lock_sock(sk);
-+ __l2cap_sock_close(sk, ECONNRESET);
-+ release_sock(sk);
-+ l2cap_sock_kill(sk);
-+}
-+
-+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
-+{
-+ struct l2cap_pinfo *pi = l2cap_pi(sk);
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (parent) {
-+ sk->type = parent->type;
-+ pi->imtu = l2cap_pi(parent)->imtu;
-+ pi->omtu = l2cap_pi(parent)->omtu;
-+ pi->link_mode = l2cap_pi(parent)->link_mode;
-+ } else {
-+ pi->imtu = L2CAP_DEFAULT_MTU;
-+ pi->omtu = 0;
-+ pi->link_mode = 0;
-+ }
-+
-+ /* Default config options */
-+ pi->conf_mtu = L2CAP_DEFAULT_MTU;
-+ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
-+}
-+
-+static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+ struct sock *sk;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-+ return NULL;
-+
-+ bluez_sock_init(sock, sk);
-+
-+ sk->zapped = 0;
-+
-+ sk->destruct = l2cap_sock_destruct;
-+ sk->sndtimeo = L2CAP_CONN_TIMEOUT;
-+
-+ sk->protocol = proto;
-+ sk->state = BT_OPEN;
-+
-+ l2cap_sock_init_timer(sk);
-+
-+ bluez_sock_link(&l2cap_sk_list, sk);
-+
-+ MOD_INC_USE_COUNT;
-+ return sk;
-+}
-+
-+static int l2cap_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ sock->state = SS_UNCONNECTED;
-+
-+ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
-+ return -EPERM;
-+
-+ sock->ops = &l2cap_sock_ops;
-+
-+ if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ l2cap_sock_init(sk, NULL);
-+ return 0;
-+}
-+
-+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
-+
-+ if (!addr || addr->sa_family != AF_BLUETOOTH)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_OPEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ write_lock_bh(&l2cap_sk_list.lock);
-+ if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
-+ err = -EADDRINUSE;
-+ } else {
-+ /* Save source address */
-+ bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
-+ l2cap_pi(sk)->psm = la->l2_psm;
-+ sk->sport = la->l2_psm;
-+ sk->state = BT_BOUND;
-+ }
-+ write_unlock_bh(&l2cap_sk_list.lock);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_do_connect(struct sock *sk)
-+{
-+ bdaddr_t *src = &bluez_pi(sk)->src;
-+ bdaddr_t *dst = &bluez_pi(sk)->dst;
-+ struct l2cap_conn *conn;
-+ struct hci_conn *hcon;
-+ struct hci_dev *hdev;
-+ int err = 0;
-+
-+ BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
-+
-+ if (!(hdev = hci_get_route(dst, src)))
-+ return -EHOSTUNREACH;
-+
-+ hci_dev_lock_bh(hdev);
-+
-+ err = -ENOMEM;
-+
-+ hcon = hci_connect(hdev, ACL_LINK, dst);
-+ if (!hcon)
-+ goto done;
-+
-+ conn = l2cap_conn_add(hcon, 0);
-+ if (!conn) {
-+ hci_conn_put(hcon);
-+ goto done;
-+ }
-+
-+ err = 0;
-+
-+ /* Update source addr of the socket */
-+ bacpy(src, conn->src);
-+
-+ l2cap_chan_add(conn, sk, NULL);
-+
-+ sk->state = BT_CONNECT;
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+ if (hcon->state == BT_CONNECTED) {
-+ if (sk->type == SOCK_SEQPACKET) {
-+ l2cap_conn_req req;
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ req.psm = l2cap_pi(sk)->psm;
-+ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-+ } else {
-+ l2cap_sock_clear_timer(sk);
-+ sk->state = BT_CONNECTED;
-+ }
-+ }
-+
-+done:
-+ hci_dev_unlock_bh(hdev);
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
-+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-+ err = -EINVAL;
-+ goto done;
-+ }
-+
-+ if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
-+ err = -EINVAL;
-+ goto done;
-+ }
-+
-+ switch(sk->state) {
-+ case BT_CONNECT:
-+ case BT_CONNECT2:
-+ case BT_CONFIG:
-+ /* Already connecting */
-+ goto wait;
-+
-+ case BT_CONNECTED:
-+ /* Already connected */
-+ goto done;
-+
-+ case BT_OPEN:
-+ case BT_BOUND:
-+ /* Can connect */
-+ break;
-+
-+ default:
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ /* Set destination address and psm */
-+ bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
-+ l2cap_pi(sk)->psm = la->l2_psm;
-+
-+ if ((err = l2cap_do_connect(sk)))
-+ goto done;
-+
-+wait:
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int l2cap_sock_listen(struct socket *sock, int backlog)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ if (!l2cap_pi(sk)->psm) {
-+ err = -EINVAL;
-+ goto done;
-+ }
-+
-+ sk->max_ack_backlog = backlog;
-+ sk->ack_backlog = 0;
-+ sk->state = BT_LISTEN;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct sock *sk = sock->sk, *nsk;
-+ long timeo;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+ BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+ /* Wait for an incoming connection. (wake-one). */
-+ add_wait_queue_exclusive(sk->sleep, &wait);
-+ while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ if (err)
-+ goto done;
-+
-+ newsock->state = SS_CONNECTED;
-+
-+ BT_DBG("new socket %p", nsk);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ addr->sa_family = AF_BLUETOOTH;
-+ *len = sizeof(struct sockaddr_l2);
-+
-+ if (peer)
-+ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
-+ else
-+ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
-+
-+ la->l2_psm = l2cap_pi(sk)->psm;
-+ return 0;
-+}
-+
-+static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (sk->err)
-+ return sock_error(sk);
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ /* Check outgoing MTU */
-+ if (len > l2cap_pi(sk)->omtu)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state == BT_CONNECTED)
-+ err = l2cap_chan_send(sk, msg, len);
-+ else
-+ err = -ENOTCONN;
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ struct l2cap_options opts;
-+ int err = 0, len;
-+ __u32 opt;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ case L2CAP_OPTIONS:
-+ len = MIN(sizeof(opts), optlen);
-+ if (copy_from_user((char *)&opts, optval, len)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+ l2cap_pi(sk)->imtu = opts.imtu;
-+ l2cap_pi(sk)->omtu = opts.omtu;
-+ break;
-+
-+ case L2CAP_LM:
-+ if (get_user(opt, (__u32 *)optval)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ l2cap_pi(sk)->link_mode = opt;
-+ break;
-+
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ struct l2cap_options opts;
-+ struct l2cap_conninfo cinfo;
-+ int len, err = 0;
-+
-+ if (get_user(len, optlen))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ case L2CAP_OPTIONS:
-+ opts.imtu = l2cap_pi(sk)->imtu;
-+ opts.omtu = l2cap_pi(sk)->omtu;
-+ opts.flush_to = l2cap_pi(sk)->flush_to;
-+
-+ len = MIN(len, sizeof(opts));
-+ if (copy_to_user(optval, (char *)&opts, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ case L2CAP_LM:
-+ if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))
-+ err = -EFAULT;
-+ break;
-+
-+ case L2CAP_CONNINFO:
-+ if (sk->state != BT_CONNECTED) {
-+ err = -ENOTCONN;
-+ break;
-+ }
-+
-+ cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
-+
-+ len = MIN(len, sizeof(cinfo));
-+ if (copy_to_user(optval, (char *)&cinfo, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_shutdown(struct socket *sock, int how)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ lock_sock(sk);
-+ if (!sk->shutdown) {
-+ sk->shutdown = SHUTDOWN_MASK;
-+ l2cap_sock_clear_timer(sk);
-+ __l2cap_sock_close(sk, 0);
-+
-+ if (sk->linger)
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ }
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int l2cap_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+ int err;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ err = l2cap_sock_shutdown(sock, 2);
-+
-+ sock_orphan(sk);
-+ l2cap_sock_kill(sk);
-+ return err;
-+}
-+
-+/* --------- L2CAP channels --------- */
-+static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+ struct sock *s;
-+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-+ if (l2cap_pi(s)->dcid == cid)
-+ break;
-+ }
-+ return s;
-+}
-+
-+static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+ struct sock *s;
-+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-+ if (l2cap_pi(s)->scid == cid)
-+ break;
-+ }
-+ return s;
-+}
-+
-+/* Find channel with given SCID.
-+ * Returns locked socket */
-+static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+ struct sock *s;
-+ read_lock(&l->lock);
-+ s = __l2cap_get_chan_by_scid(l, cid);
-+ if (s) bh_lock_sock(s);
-+ read_unlock(&l->lock);
-+ return s;
-+}
-+
-+static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
-+{
-+ __u16 cid = 0x0040;
-+
-+ for (; cid < 0xffff; cid++) {
-+ if(!__l2cap_get_chan_by_scid(l, cid))
-+ return cid;
-+ }
-+
-+ return 0;
-+}
-+
-+static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
-+{
-+ sock_hold(sk);
-+
-+ if (l->head)
-+ l2cap_pi(l->head)->prev_c = sk;
-+
-+ l2cap_pi(sk)->next_c = l->head;
-+ l2cap_pi(sk)->prev_c = NULL;
-+ l->head = sk;
-+}
-+
-+static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
-+{
-+ struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
-+
-+ write_lock(&l->lock);
-+ if (sk == l->head)
-+ l->head = next;
-+
-+ if (next)
-+ l2cap_pi(next)->prev_c = prev;
-+ if (prev)
-+ l2cap_pi(prev)->next_c = next;
-+ write_unlock(&l->lock);
-+
-+ __sock_put(sk);
-+}
-+
-+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+
-+ BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
-+
-+ l2cap_pi(sk)->conn = conn;
-+
-+ if (sk->type == SOCK_SEQPACKET) {
-+ /* Alloc CID for connection-oriented socket */
-+ l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
-+ } else if (sk->type == SOCK_DGRAM) {
-+ /* Connectionless socket */
-+ l2cap_pi(sk)->scid = 0x0002;
-+ l2cap_pi(sk)->dcid = 0x0002;
-+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-+ } else {
-+ /* Raw socket can send/recv signalling messages only */
-+ l2cap_pi(sk)->scid = 0x0001;
-+ l2cap_pi(sk)->dcid = 0x0001;
-+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-+ }
-+
-+ __l2cap_chan_link(l, sk);
-+
-+ if (parent)
-+ bluez_accept_enqueue(parent, sk);
-+}
-+
-+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ write_lock(&l->lock);
-+ __l2cap_chan_add(conn, sk, parent);
-+ write_unlock(&l->lock);
-+}
-+
-+/* Delete channel.
-+ * Must be called on the locked socket. */
-+static void l2cap_chan_del(struct sock *sk, int err)
-+{
-+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+ struct sock *parent = bluez_pi(sk)->parent;
-+
-+ l2cap_sock_clear_timer(sk);
-+
-+ BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-+
-+ if (conn) {
-+ /* Unlink from channel list */
-+ l2cap_chan_unlink(&conn->chan_list, sk);
-+ l2cap_pi(sk)->conn = NULL;
-+ hci_conn_put(conn->hcon);
-+ }
-+
-+ sk->state = BT_CLOSED;
-+ sk->zapped = 1;
-+
-+ if (err)
-+ sk->err = err;
-+
-+ if (parent)
-+ parent->data_ready(parent, 0);
-+ else
-+ sk->state_change(sk);
-+}
-+
-+static void l2cap_conn_ready(struct l2cap_conn *conn)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sock *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ bh_lock_sock(sk);
-+
-+ if (sk->type != SOCK_SEQPACKET) {
-+ l2cap_sock_clear_timer(sk);
-+ sk->state = BT_CONNECTED;
-+ sk->state_change(sk);
-+ } else if (sk->state == BT_CONNECT) {
-+ l2cap_conn_req req;
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ req.psm = l2cap_pi(sk)->psm;
-+ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-+ }
-+
-+ bh_unlock_sock(sk);
-+ }
-+
-+ read_unlock(&l->lock);
-+}
-+
-+/* Notify sockets that we cannot guaranty reliability anymore */
-+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sock *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
-+ sk->err = err;
-+ }
-+ read_unlock(&l->lock);
-+}
-+
-+static void l2cap_chan_ready(struct sock *sk)
-+{
-+ struct sock *parent = bluez_pi(sk)->parent;
-+
-+ BT_DBG("sk %p, parent %p", sk, parent);
-+
-+ l2cap_pi(sk)->conf_state = 0;
-+ l2cap_sock_clear_timer(sk);
-+
-+ if (!parent) {
-+ /* Outgoing channel.
-+ * Wake up socket sleeping on connect.
-+ */
-+ sk->state = BT_CONNECTED;
-+ sk->state_change(sk);
-+ } else {
-+ /* Incomming channel.
-+ * Wake up socket sleeping on accept.
-+ */
-+ parent->data_ready(parent, 0);
-+ }
-+}
-+
-+/* Copy frame to all raw sockets on that connection */
-+void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+ struct l2cap_chan_list *l = &conn->chan_list;
-+ struct sk_buff *nskb;
-+ struct sock * sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ if (sk->type != SOCK_RAW)
-+ continue;
-+
-+ /* Don't send frame to the socket it came from */
-+ if (skb->sk == sk)
-+ continue;
-+
-+ if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
-+ continue;
-+
-+ if (sock_queue_rcv_skb(sk, nskb))
-+ kfree_skb(nskb);
-+ }
-+ read_unlock(&l->lock);
-+}
-+
-+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
-+{
-+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+ struct sk_buff *skb, **frag;
-+ int err, hlen, count, sent=0;
-+ l2cap_hdr *lh;
-+
-+ BT_DBG("sk %p len %d", sk, len);
-+
-+ /* First fragment (with L2CAP header) */
-+ if (sk->type == SOCK_DGRAM)
-+ hlen = L2CAP_HDR_SIZE + 2;
-+ else
-+ hlen = L2CAP_HDR_SIZE;
-+
-+ count = MIN(conn->mtu - hlen, len);
-+
-+ skb = bluez_skb_send_alloc(sk, hlen + count,
-+ msg->msg_flags & MSG_DONTWAIT, &err);
-+ if (!skb)
-+ return err;
-+
-+ /* Create L2CAP header */
-+ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-+ lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-+
-+ if (sk->type == SOCK_DGRAM)
-+ put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
-+
-+ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-+ err = -EFAULT;
-+ goto fail;
-+ }
-+
-+ sent += count;
-+ len -= count;
-+
-+ /* Continuation fragments (no L2CAP header) */
-+ frag = &skb_shinfo(skb)->frag_list;
-+ while (len) {
-+ count = MIN(conn->mtu, len);
-+
-+ *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
-+ if (!*frag)
-+ goto fail;
-+
-+ if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
-+ err = -EFAULT;
-+ goto fail;
-+ }
-+
-+ sent += count;
-+ len -= count;
-+
-+ frag = &(*frag)->next;
-+ }
-+
-+ if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
-+ goto fail;
-+
-+ return sent;
-+
-+fail:
-+ kfree_skb(skb);
-+ return err;
-+}
-+
-+/* --------- L2CAP signalling commands --------- */
-+static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
-+{
-+ __u8 id;
-+
-+ /* Get next available identificator.
-+ * 1 - 199 are used by kernel.
-+ * 200 - 254 are used by utilities like l2ping, etc
-+ */
-+
-+ spin_lock(&conn->lock);
-+
-+ if (++conn->tx_ident > 199)
-+ conn->tx_ident = 1;
-+
-+ id = conn->tx_ident;
-+
-+ spin_unlock(&conn->lock);
-+
-+ return id;
-+}
-+
-+static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
-+ __u8 code, __u8 ident, __u16 dlen, void *data)
-+{
-+ struct sk_buff *skb, **frag;
-+ l2cap_cmd_hdr *cmd;
-+ l2cap_hdr *lh;
-+ int len, count;
-+
-+ BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
-+
-+ len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
-+ count = MIN(conn->mtu, len);
-+
-+ skb = bluez_skb_alloc(count, GFP_ATOMIC);
-+ if (!skb)
-+ return NULL;
-+
-+ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-+ lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-+ lh->cid = __cpu_to_le16(0x0001);
-+
-+ cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
-+ cmd->code = code;
-+ cmd->ident = ident;
-+ cmd->len = __cpu_to_le16(dlen);
-+
-+ if (dlen) {
-+ count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
-+ memcpy(skb_put(skb, count), data, count);
-+ data += count;
-+ }
-+
-+ len -= skb->len;
-+
-+ /* Continuation fragments (no L2CAP header) */
-+ frag = &skb_shinfo(skb)->frag_list;
-+ while (len) {
-+ count = MIN(conn->mtu, len);
-+
-+ *frag = bluez_skb_alloc(count, GFP_ATOMIC);
-+ if (!*frag)
-+ goto fail;
-+
-+ memcpy(skb_put(*frag, count), data, count);
-+
-+ len -= count;
-+ data += count;
-+
-+ frag = &(*frag)->next;
-+ }
-+
-+ return skb;
-+
-+fail:
-+ kfree_skb(skb);
-+ return NULL;
-+}
-+
-+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
-+{
-+ __u8 ident = l2cap_get_ident(conn);
-+ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-+
-+ BT_DBG("code 0x%2.2x", code);
-+
-+ if (!skb)
-+ return -ENOMEM;
-+ return hci_send_acl(conn->hcon, skb, 0);
-+}
-+
-+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
-+{
-+ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-+
-+ BT_DBG("code 0x%2.2x", code);
-+
-+ if (!skb)
-+ return -ENOMEM;
-+ return hci_send_acl(conn->hcon, skb, 0);
-+}
-+
-+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
-+{
-+ l2cap_conf_opt *opt = *ptr;
-+ int len;
-+
-+ len = L2CAP_CONF_OPT_SIZE + opt->len;
-+ *ptr += len;
-+
-+ *type = opt->type;
-+ *olen = opt->len;
-+
-+ switch (opt->len) {
-+ case 1:
-+ *val = *((__u8 *) opt->val);
-+ break;
-+
-+ case 2:
-+ *val = __le16_to_cpu(*((__u16 *)opt->val));
-+ break;
-+
-+ case 4:
-+ *val = __le32_to_cpu(*((__u32 *)opt->val));
-+ break;
-+
-+ default:
-+ *val = (unsigned long) opt->val;
-+ break;
-+ };
-+
-+ BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
-+ return len;
-+}
-+
-+static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len)
-+{
-+ int type, hint, olen;
-+ unsigned long val;
-+ void *ptr = data;
-+
-+ BT_DBG("sk %p len %d", sk, len);
-+
-+ while (len >= L2CAP_CONF_OPT_SIZE) {
-+ len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
-+
-+ hint = type & 0x80;
-+ type &= 0x7f;
-+
-+ switch (type) {
-+ case L2CAP_CONF_MTU:
-+ l2cap_pi(sk)->conf_mtu = val;
-+ break;
-+
-+ case L2CAP_CONF_FLUSH_TO:
-+ l2cap_pi(sk)->flush_to = val;
-+ break;
-+
-+ case L2CAP_CONF_QOS:
-+ break;
-+
-+ default:
-+ if (hint)
-+ break;
-+
-+ /* FIXME: Reject unknown option */
-+ break;
-+ };
-+ }
-+}
-+
-+static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val)
-+{
-+ register l2cap_conf_opt *opt = *ptr;
-+
-+ BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
-+
-+ opt->type = type;
-+ opt->len = len;
-+
-+ switch (len) {
-+ case 1:
-+ *((__u8 *) opt->val) = val;
-+ break;
-+
-+ case 2:
-+ *((__u16 *) opt->val) = __cpu_to_le16(val);
-+ break;
-+
-+ case 4:
-+ *((__u32 *) opt->val) = __cpu_to_le32(val);
-+ break;
-+
-+ default:
-+ memcpy(opt->val, (void *) val, len);
-+ break;
-+ };
-+
-+ *ptr += L2CAP_CONF_OPT_SIZE + len;
-+}
-+
-+static int l2cap_build_conf_req(struct sock *sk, void *data)
-+{
-+ struct l2cap_pinfo *pi = l2cap_pi(sk);
-+ l2cap_conf_req *req = (l2cap_conf_req *) data;
-+ void *ptr = req->data;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (pi->imtu != L2CAP_DEFAULT_MTU)
-+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
-+
-+ /* FIXME. Need actual value of the flush timeout */
-+ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-+ // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
-+
-+ req->dcid = __cpu_to_le16(pi->dcid);
-+ req->flags = __cpu_to_le16(0);
-+
-+ return ptr - data;
-+}
-+
-+static inline int l2cap_conf_output(struct sock *sk, void **ptr)
-+{
-+ struct l2cap_pinfo *pi = l2cap_pi(sk);
-+ int result = 0;
-+
-+ /* Configure output options and let the other side know
-+ * which ones we don't like.
-+ */
-+ if (pi->conf_mtu < pi->omtu) {
-+ l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
-+ result = L2CAP_CONF_UNACCEPT;
-+ } else {
-+ pi->omtu = pi->conf_mtu;
-+ }
-+
-+ BT_DBG("sk %p result %d", sk, result);
-+ return result;
-+}
-+
-+static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
-+{
-+ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
-+ void *ptr = rsp->data;
-+ u16 flags = 0;
-+
-+ BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
-+
-+ if (result)
-+ *result = l2cap_conf_output(sk, &ptr);
-+ else
-+ flags |= 0x0001;
-+
-+ rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ rsp->result = __cpu_to_le16(result ? *result : 0);
-+ rsp->flags = __cpu_to_le16(flags);
-+
-+ return ptr - data;
-+}
-+
-+static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ struct l2cap_chan_list *list = &conn->chan_list;
-+ l2cap_conn_req *req = (l2cap_conn_req *) data;
-+ l2cap_conn_rsp rsp;
-+ struct sock *sk, *parent;
-+ int result = 0, status = 0;
-+
-+ __u16 dcid = 0, scid = __le16_to_cpu(req->scid);
-+ __u16 psm = req->psm;
-+
-+ BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
-+
-+ /* Check if we have socket listening on psm */
-+ parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
-+ if (!parent) {
-+ result = L2CAP_CR_BAD_PSM;
-+ goto sendresp;
-+ }
-+
-+ result = L2CAP_CR_NO_MEM;
-+
-+ /* Check for backlog size */
-+ if (parent->ack_backlog > parent->max_ack_backlog) {
-+ BT_DBG("backlog full %d", parent->ack_backlog);
-+ goto response;
-+ }
-+
-+ sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
-+ if (!sk)
-+ goto response;
-+
-+ write_lock(&list->lock);
-+
-+ /* Check if we already have channel with that dcid */
-+ if (__l2cap_get_chan_by_dcid(list, scid)) {
-+ write_unlock(&list->lock);
-+ sk->zapped = 1;
-+ l2cap_sock_kill(sk);
-+ goto response;
-+ }
-+
-+ hci_conn_hold(conn->hcon);
-+
-+ l2cap_sock_init(sk, parent);
-+ bacpy(&bluez_pi(sk)->src, conn->src);
-+ bacpy(&bluez_pi(sk)->dst, conn->dst);
-+ l2cap_pi(sk)->psm = psm;
-+ l2cap_pi(sk)->dcid = scid;
-+
-+ __l2cap_chan_add(conn, sk, parent);
-+ dcid = l2cap_pi(sk)->scid;
-+
-+ l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+ /* Service level security */
-+ result = L2CAP_CR_PEND;
-+ status = L2CAP_CS_AUTHEN_PEND;
-+ sk->state = BT_CONNECT2;
-+ l2cap_pi(sk)->ident = cmd->ident;
-+
-+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
-+ if (!hci_conn_encrypt(conn->hcon))
-+ goto done;
-+ } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
-+ if (!hci_conn_auth(conn->hcon))
-+ goto done;
-+ }
-+
-+ sk->state = BT_CONFIG;
-+ result = status = 0;
-+
-+done:
-+ write_unlock(&list->lock);
-+
-+response:
-+ bh_unlock_sock(parent);
-+
-+sendresp:
-+ rsp.scid = __cpu_to_le16(scid);
-+ rsp.dcid = __cpu_to_le16(dcid);
-+ rsp.result = __cpu_to_le16(result);
-+ rsp.status = __cpu_to_le16(status);
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
-+ return 0;
-+}
-+
-+static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
-+ __u16 scid, dcid, result, status;
-+ struct sock *sk;
-+ char req[128];
-+
-+ scid = __le16_to_cpu(rsp->scid);
-+ dcid = __le16_to_cpu(rsp->dcid);
-+ result = __le16_to_cpu(rsp->result);
-+ status = __le16_to_cpu(rsp->status);
-+
-+ BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+ return -ENOENT;
-+
-+ switch (result) {
-+ case L2CAP_CR_SUCCESS:
-+ sk->state = BT_CONFIG;
-+ l2cap_pi(sk)->dcid = dcid;
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
-+
-+ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-+ break;
-+
-+ case L2CAP_CR_PEND:
-+ break;
-+
-+ default:
-+ l2cap_chan_del(sk, ECONNREFUSED);
-+ break;
-+ }
-+
-+ bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_conf_req * req = (l2cap_conf_req *) data;
-+ __u16 dcid, flags;
-+ __u8 rsp[64];
-+ struct sock *sk;
-+ int result;
-+
-+ dcid = __le16_to_cpu(req->dcid);
-+ flags = __le16_to_cpu(req->flags);
-+
-+ BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-+ return -ENOENT;
-+
-+ l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
-+
-+ if (flags & 0x0001) {
-+ /* Incomplete config. Send empty response. */
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
-+ goto unlock;
-+ }
-+
-+ /* Complete config. */
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
-+
-+ if (result)
-+ goto unlock;
-+
-+ /* Output config done */
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-+
-+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
-+ sk->state = BT_CONNECTED;
-+ l2cap_chan_ready(sk);
-+ } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
-+ char req[64];
-+ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-+ }
-+
-+unlock:
-+ bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
-+ __u16 scid, flags, result;
-+ struct sock *sk;
-+ int err = 0;
-+
-+ scid = __le16_to_cpu(rsp->scid);
-+ flags = __le16_to_cpu(rsp->flags);
-+ result = __le16_to_cpu(rsp->result);
-+
-+ BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+ return -ENOENT;
-+
-+ switch (result) {
-+ case L2CAP_CONF_SUCCESS:
-+ break;
-+
-+ case L2CAP_CONF_UNACCEPT:
-+ if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
-+ char req[128];
-+ /*
-+ It does not make sense to adjust L2CAP parameters
-+ that are currently defined in the spec. We simply
-+ resend config request that we sent earlier. It is
-+ stupid :) but it helps qualification testing
-+ which expects at least some response from us.
-+ */
-+ l2cap_send_req(conn, L2CAP_CONF_REQ,
-+ l2cap_build_conf_req(sk, req), req);
-+ goto done;
-+ }
-+ default:
-+ sk->state = BT_DISCONN;
-+ sk->err = ECONNRESET;
-+ l2cap_sock_set_timer(sk, HZ * 5);
-+ {
-+ l2cap_disconn_req req;
-+ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+ }
-+ goto done;
-+ }
-+
-+ if (flags & 0x01)
-+ goto done;
-+
-+ /* Input config done */
-+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
-+
-+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
-+ sk->state = BT_CONNECTED;
-+ l2cap_chan_ready(sk);
-+ }
-+
-+done:
-+ bh_unlock_sock(sk);
-+ return err;
-+}
-+
-+static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_disconn_req *req = (l2cap_disconn_req *) data;
-+ l2cap_disconn_rsp rsp;
-+ __u16 dcid, scid;
-+ struct sock *sk;
-+
-+ scid = __le16_to_cpu(req->scid);
-+ dcid = __le16_to_cpu(req->dcid);
-+
-+ BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-+ return 0;
-+
-+ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
-+
-+ sk->shutdown = SHUTDOWN_MASK;
-+
-+ l2cap_chan_del(sk, ECONNRESET);
-+ bh_unlock_sock(sk);
-+
-+ l2cap_sock_kill(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+ l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
-+ __u16 dcid, scid;
-+ struct sock *sk;
-+
-+ scid = __le16_to_cpu(rsp->scid);
-+ dcid = __le16_to_cpu(rsp->dcid);
-+
-+ BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
-+
-+ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+ return 0;
-+ l2cap_chan_del(sk, 0);
-+ bh_unlock_sock(sk);
-+
-+ l2cap_sock_kill(sk);
-+ return 0;
-+}
-+
-+static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+ __u8 *data = skb->data;
-+ int len = skb->len;
-+ l2cap_cmd_hdr cmd;
-+ int err = 0;
-+
-+ while (len >= L2CAP_CMD_HDR_SIZE) {
-+ memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-+ data += L2CAP_CMD_HDR_SIZE;
-+ len -= L2CAP_CMD_HDR_SIZE;
-+
-+ cmd.len = __le16_to_cpu(cmd.len);
-+
-+ BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
-+
-+ if (cmd.len > len || !cmd.ident) {
-+ BT_DBG("corrupted command");
-+ break;
-+ }
-+
-+ switch (cmd.code) {
-+ case L2CAP_CONN_REQ:
-+ err = l2cap_connect_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_CONN_RSP:
-+ err = l2cap_connect_rsp(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_CONF_REQ:
-+ err = l2cap_config_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_CONF_RSP:
-+ err = l2cap_config_rsp(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_DISCONN_REQ:
-+ err = l2cap_disconnect_req(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_DISCONN_RSP:
-+ err = l2cap_disconnect_rsp(conn, &cmd, data);
-+ break;
-+
-+ case L2CAP_COMMAND_REJ:
-+ /* FIXME: We should process this */
-+ l2cap_raw_recv(conn, skb);
-+ break;
-+
-+ case L2CAP_ECHO_REQ:
-+ l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
-+ break;
-+
-+ case L2CAP_ECHO_RSP:
-+ case L2CAP_INFO_REQ:
-+ case L2CAP_INFO_RSP:
-+ l2cap_raw_recv(conn, skb);
-+ break;
-+
-+ default:
-+ BT_ERR("Uknown signaling command 0x%2.2x", cmd.code);
-+ err = -EINVAL;
-+ break;
-+ };
-+
-+ if (err) {
-+ l2cap_cmd_rej rej;
-+ BT_DBG("error %d", err);
-+
-+ /* FIXME: Map err to a valid reason. */
-+ rej.reason = __cpu_to_le16(0);
-+ l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
-+ }
-+
-+ data += cmd.len;
-+ len -= cmd.len;
-+ }
-+
-+ kfree_skb(skb);
-+}
-+
-+static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
-+{
-+ struct sock *sk;
-+
-+ sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
-+ if (!sk) {
-+ BT_DBG("unknown cid 0x%4.4x", cid);
-+ goto drop;
-+ }
-+
-+ BT_DBG("sk %p, len %d", sk, skb->len);
-+
-+ if (sk->state != BT_CONNECTED)
-+ goto drop;
-+
-+ if (l2cap_pi(sk)->imtu < skb->len)
-+ goto drop;
-+
-+ /* If socket recv buffers overflows we drop data here
-+ * which is *bad* because L2CAP has to be reliable.
-+ * But we don't have any other choice. L2CAP doesn't
-+ * provide flow control mechanism */
-+
-+ if (!sock_queue_rcv_skb(sk, skb))
-+ goto done;
-+
-+drop:
-+ kfree_skb(skb);
-+
-+done:
-+ if (sk) bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
-+{
-+ struct sock *sk;
-+
-+ sk = l2cap_get_sock_by_psm(0, psm, conn->src);
-+ if (!sk)
-+ goto drop;
-+
-+ BT_DBG("sk %p, len %d", sk, skb->len);
-+
-+ if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
-+ goto drop;
-+
-+ if (l2cap_pi(sk)->imtu < skb->len)
-+ goto drop;
-+
-+ if (!sock_queue_rcv_skb(sk, skb))
-+ goto done;
-+
-+drop:
-+ kfree_skb(skb);
-+
-+done:
-+ if (sk) bh_unlock_sock(sk);
-+ return 0;
-+}
-+
-+static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+ l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-+ __u16 cid, psm, len;
-+
-+ skb_pull(skb, L2CAP_HDR_SIZE);
-+ cid = __le16_to_cpu(lh->cid);
-+ len = __le16_to_cpu(lh->len);
-+
-+ BT_DBG("len %d, cid 0x%4.4x", len, cid);
-+
-+ switch (cid) {
-+ case 0x0001:
-+ l2cap_sig_channel(conn, skb);
-+ break;
-+
-+ case 0x0002:
-+ psm = get_unaligned((__u16 *) skb->data);
-+ skb_pull(skb, 2);
-+ l2cap_conless_channel(conn, psm, skb);
-+ break;
-+
-+ default:
-+ l2cap_data_channel(conn, cid, skb);
-+ break;
-+ }
-+}
-+
-+/* ------------ L2CAP interface with lower layer (HCI) ------------- */
-+
-+static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+ int exact = 0, lm1 = 0, lm2 = 0;
-+ register struct sock *sk;
-+
-+ if (type != ACL_LINK)
-+ return 0;
-+
-+ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-+
-+ /* Find listening sockets and check their link_mode */
-+ read_lock(&l2cap_sk_list.lock);
-+ for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+ if (sk->state != BT_LISTEN)
-+ continue;
-+
-+ if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) {
-+ lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
-+ exact++;
-+ } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
-+ }
-+ read_unlock(&l2cap_sk_list.lock);
-+
-+ return exact ? lm1 : lm2;
-+}
-+
-+static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-+
-+ if (hcon->type != ACL_LINK)
-+ return 0;
-+
-+ if (!status) {
-+ struct l2cap_conn *conn;
-+
-+ conn = l2cap_conn_add(hcon, status);
-+ if (conn)
-+ l2cap_conn_ready(conn);
-+ } else
-+ l2cap_conn_del(hcon, bterr(status));
-+
-+ return 0;
-+}
-+
-+static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason)
-+{
-+ BT_DBG("hcon %p reason %d", hcon, reason);
-+
-+ if (hcon->type != ACL_LINK)
-+ return 0;
-+
-+ l2cap_conn_del(hcon, bterr(reason));
-+ return 0;
-+}
-+
-+static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ struct l2cap_chan_list *l;
-+ struct l2cap_conn *conn;
-+ l2cap_conn_rsp rsp;
-+ struct sock *sk;
-+ int result;
-+
-+ if (!(conn = hcon->l2cap_data))
-+ return 0;
-+ l = &conn->chan_list;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ bh_lock_sock(sk);
-+
-+ if (sk->state != BT_CONNECT2 ||
-+ (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) {
-+ bh_unlock_sock(sk);
-+ continue;
-+ }
-+
-+ if (!status) {
-+ sk->state = BT_CONFIG;
-+ result = 0;
-+ } else {
-+ sk->state = BT_DISCONN;
-+ l2cap_sock_set_timer(sk, HZ/10);
-+ result = L2CAP_CR_SEC_BLOCK;
-+ }
-+
-+ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ rsp.result = __cpu_to_le16(result);
-+ rsp.status = __cpu_to_le16(0);
-+ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
-+ L2CAP_CONN_RSP_SIZE, &rsp);
-+
-+ bh_unlock_sock(sk);
-+ }
-+
-+ read_unlock(&l->lock);
-+ return 0;
-+}
-+
-+static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ struct l2cap_chan_list *l;
-+ struct l2cap_conn *conn;
-+ l2cap_conn_rsp rsp;
-+ struct sock *sk;
-+ int result;
-+
-+ if (!(conn = hcon->l2cap_data))
-+ return 0;
-+ l = &conn->chan_list;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ read_lock(&l->lock);
-+
-+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+ bh_lock_sock(sk);
-+
-+ if (sk->state != BT_CONNECT2) {
-+ bh_unlock_sock(sk);
-+ continue;
-+ }
-+
-+ if (!status) {
-+ sk->state = BT_CONFIG;
-+ result = 0;
-+ } else {
-+ sk->state = BT_DISCONN;
-+ l2cap_sock_set_timer(sk, HZ/10);
-+ result = L2CAP_CR_SEC_BLOCK;
-+ }
-+
-+ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+ rsp.result = __cpu_to_le16(result);
-+ rsp.status = __cpu_to_le16(0);
-+ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
-+ L2CAP_CONN_RSP_SIZE, &rsp);
-+
-+ bh_unlock_sock(sk);
-+ }
-+
-+ read_unlock(&l->lock);
-+ return 0;
-+}
-+
-+static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags)
-+{
-+ struct l2cap_conn *conn = hcon->l2cap_data;
-+
-+ if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
-+ goto drop;
-+
-+ BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
-+
-+ if (flags & ACL_START) {
-+ l2cap_hdr *hdr;
-+ int len;
-+
-+ if (conn->rx_len) {
-+ BT_ERR("Unexpected start frame (len %d)", skb->len);
-+ kfree_skb(conn->rx_skb);
-+ conn->rx_skb = NULL;
-+ conn->rx_len = 0;
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ }
-+
-+ if (skb->len < 2) {
-+ BT_ERR("Frame is too short (len %d)", skb->len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ hdr = (l2cap_hdr *) skb->data;
-+ len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
-+
-+ if (len == skb->len) {
-+ /* Complete frame received */
-+ l2cap_recv_frame(conn, skb);
-+ return 0;
-+ }
-+
-+ BT_DBG("Start: total len %d, frag len %d", len, skb->len);
-+
-+ if (skb->len > len) {
-+ BT_ERR("Frame is too long (len %d, expected len %d)",
-+ skb->len, len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ /* Allocate skb for the complete frame including header */
-+ conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+ if (!conn->rx_skb)
-+ goto drop;
-+
-+ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-+ conn->rx_len = len - skb->len;
-+ } else {
-+ BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
-+
-+ if (!conn->rx_len) {
-+ BT_ERR("Unexpected continuation frame (len %d)", skb->len);
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ if (skb->len > conn->rx_len) {
-+ BT_ERR("Fragment is too long (len %d, expected %d)",
-+ skb->len, conn->rx_len);
-+ kfree_skb(conn->rx_skb);
-+ conn->rx_skb = NULL;
-+ conn->rx_len = 0;
-+ l2cap_conn_unreliable(conn, ECOMM);
-+ goto drop;
-+ }
-+
-+ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-+ conn->rx_len -= skb->len;
-+
-+ if (!conn->rx_len) {
-+ /* Complete frame received */
-+ l2cap_recv_frame(conn, conn->rx_skb);
-+ conn->rx_skb = NULL;
-+ }
-+ }
-+
-+drop:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+/* ----- Proc fs support ------ */
-+static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
-+{
-+ struct l2cap_pinfo *pi;
-+ struct sock *sk;
-+ char *ptr = buf;
-+
-+ read_lock_bh(&list->lock);
-+
-+ for (sk = list->head; sk; sk = sk->next) {
-+ pi = l2cap_pi(sk);
-+ ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
-+ pi->link_mode);
-+ }
-+
-+ read_unlock_bh(&list->lock);
-+
-+ ptr += sprintf(ptr, "\n");
-+ return ptr - buf;
-+}
-+
-+static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+ char *ptr = buf;
-+ int len;
-+
-+ BT_DBG("count %d, offset %ld", count, offset);
-+
-+ ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
-+ len = ptr - buf;
-+
-+ if (len <= count + offset)
-+ *eof = 1;
-+
-+ *start = buf + offset;
-+ len -= offset;
-+
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+
-+static struct proto_ops l2cap_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: l2cap_sock_release,
-+ bind: l2cap_sock_bind,
-+ connect: l2cap_sock_connect,
-+ listen: l2cap_sock_listen,
-+ accept: l2cap_sock_accept,
-+ getname: l2cap_sock_getname,
-+ sendmsg: l2cap_sock_sendmsg,
-+ recvmsg: bluez_sock_recvmsg,
-+ poll: bluez_sock_poll,
-+ socketpair: sock_no_socketpair,
-+ ioctl: sock_no_ioctl,
-+ shutdown: l2cap_sock_shutdown,
-+ setsockopt: l2cap_sock_setsockopt,
-+ getsockopt: l2cap_sock_getsockopt,
-+ mmap: sock_no_mmap
-+};
-+
-+static struct net_proto_family l2cap_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: l2cap_sock_create
-+};
-+
-+static struct hci_proto l2cap_hci_proto = {
-+ name: "L2CAP",
-+ id: HCI_PROTO_L2CAP,
-+ connect_ind: l2cap_connect_ind,
-+ connect_cfm: l2cap_connect_cfm,
-+ disconn_ind: l2cap_disconn_ind,
-+ recv_acldata: l2cap_recv_acldata,
-+ auth_cfm: l2cap_auth_cfm,
-+ encrypt_cfm: l2cap_encrypt_cfm
-+};
-+
-+int __init l2cap_init(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
-+ BT_ERR("Can't register L2CAP socket");
-+ return err;
-+ }
-+
-+ if ((err = hci_register_proto(&l2cap_hci_proto))) {
-+ BT_ERR("Can't register L2CAP protocol");
-+ return err;
-+ }
-+
-+ create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
-+
-+ BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ return 0;
-+}
-+
-+void l2cap_cleanup(void)
-+{
-+ remove_proc_entry("bluetooth/l2cap", NULL);
-+
-+ /* Unregister socket and protocol */
-+ if (bluez_sock_unregister(BTPROTO_L2CAP))
-+ BT_ERR("Can't unregister L2CAP socket");
-+
-+ if (hci_unregister_proto(&l2cap_hci_proto))
-+ BT_ERR("Can't unregister L2CAP protocol");
-+}
-+
-+void l2cap_load(void)
-+{
-+ /* Dummy function to trigger automatic L2CAP module loading by
-+ other modules that use L2CAP sockets but do not use any other
-+ symbols from it. */
-+ return;
-+}
-+
-+EXPORT_SYMBOL(l2cap_load);
-+
-+module_init(l2cap_init);
-+module_exit(l2cap_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/l2cap_core.c linux-2.4.18-mh9/net/bluetooth/l2cap_core.c
---- linux-2.4.18/net/bluetooth/l2cap_core.c Sun Sep 30 21:26:08 2001
-+++ linux-2.4.18-mh9/net/bluetooth/l2cap_core.c Thu Jan 1 01:00:00 1970
-@@ -1,2316 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * BlueZ L2CAP core and sockets.
-- *
-- * $Id$
-- */
--#define VERSION "1.1"
--
--#include <linux/config.h>
--#include <linux/module.h>
--
--#include <linux/types.h>
--#include <linux/errno.h>
--#include <linux/kernel.h>
--#include <linux/major.h>
--#include <linux/sched.h>
--#include <linux/slab.h>
--#include <linux/poll.h>
--#include <linux/fcntl.h>
--#include <linux/init.h>
--#include <linux/skbuff.h>
--#include <linux/interrupt.h>
--#include <linux/socket.h>
--#include <linux/skbuff.h>
--#include <linux/proc_fs.h>
--#include <linux/list.h>
--#include <net/sock.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/l2cap.h>
--#include <net/bluetooth/l2cap_core.h>
--
--#ifndef L2CAP_DEBUG
--#undef DBG
--#define DBG( A... )
--#endif
--
--struct proto_ops l2cap_sock_ops;
--
--struct bluez_sock_list l2cap_sk_list = {
-- lock: RW_LOCK_UNLOCKED
--};
--
--struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
--rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
--
--static int l2cap_conn_del(struct l2cap_conn *conn, int err);
--
--static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
--static void l2cap_chan_del(struct sock *sk, int err);
--static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
--
--static void l2cap_sock_close(struct sock *sk);
--static void l2cap_sock_kill(struct sock *sk);
--
--static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
--static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
--
--/* -------- L2CAP interfaces & routing --------- */
--/* Add/delete L2CAP interface.
-- * Must be called with locked rt_lock
-- */
--
--static void l2cap_iff_add(struct hci_dev *hdev)
--{
-- struct l2cap_iff *iff;
--
-- DBG("%s", hdev->name);
--
-- DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
--
-- /* Allocate new interface and lock HCI device */
-- if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
-- ERR("Can't allocate new interface %s", hdev->name);
-- return;
-- }
-- memset(iff, 0, sizeof(struct l2cap_iff));
--
-- hci_dev_hold(hdev);
-- hdev->l2cap_data = iff;
-- iff->hdev = hdev;
-- iff->mtu = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
-- iff->bdaddr = &hdev->bdaddr;
--
-- spin_lock_init(&iff->lock);
-- INIT_LIST_HEAD(&iff->conn_list);
--
-- list_add(&iff->list, &l2cap_iff_list);
--}
--
--static void l2cap_iff_del(struct hci_dev *hdev)
--{
-- struct l2cap_iff *iff;
--
-- if (!(iff = hdev->l2cap_data))
-- return;
--
-- DBG("%s iff %p", hdev->name, iff);
--
-- list_del(&iff->list);
--
-- l2cap_iff_lock(iff);
--
-- /* Drop connections */
-- while (!list_empty(&iff->conn_list)) {
-- struct l2cap_conn *c;
--
-- c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
-- l2cap_conn_del(c, ENODEV);
-- }
--
-- l2cap_iff_unlock(iff);
--
-- /* Unlock HCI device */
-- hdev->l2cap_data = NULL;
-- hci_dev_put(hdev);
--
-- kfree(iff);
--}
--
--/* Get route. Returns L2CAP interface.
-- * Must be called with locked rt_lock
-- */
--static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
--{
-- struct list_head *p;
-- int use_src;
--
-- DBG("%s -> %s", batostr(src), batostr(dst));
--
-- use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
--
-- /* Simple routing:
-- * No source address - find interface with bdaddr != dst
-- * Source address - find interface with bdaddr == src
-- */
--
-- list_for_each(p, &l2cap_iff_list) {
-- struct l2cap_iff *iff;
--
-- iff = list_entry(p, struct l2cap_iff, list);
--
-- if (use_src && !bacmp(iff->bdaddr, src))
-- return iff;
-- else if (bacmp(iff->bdaddr, dst))
-- return iff;
-- }
-- return NULL;
--}
--
--/* ----- L2CAP timers ------ */
--static void l2cap_sock_timeout(unsigned long arg)
--{
-- struct sock *sk = (struct sock *) arg;
--
-- DBG("sock %p state %d", sk, sk->state);
--
-- bh_lock_sock(sk);
-- switch (sk->state) {
-- case BT_DISCONN:
-- l2cap_chan_del(sk, ETIMEDOUT);
-- break;
--
-- default:
-- sk->err = ETIMEDOUT;
-- sk->state_change(sk);
-- break;
-- };
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
-- sock_put(sk);
--}
--
--static void l2cap_sock_set_timer(struct sock *sk, long timeout)
--{
-- DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
--
-- if (!mod_timer(&sk->timer, jiffies + timeout))
-- sock_hold(sk);
--}
--
--static void l2cap_sock_clear_timer(struct sock *sk)
--{
-- DBG("sock %p state %d", sk, sk->state);
--
-- if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-- __sock_put(sk);
--}
--
--static void l2cap_sock_init_timer(struct sock *sk)
--{
-- init_timer(&sk->timer);
-- sk->timer.function = l2cap_sock_timeout;
-- sk->timer.data = (unsigned long)sk;
--}
--
--static void l2cap_conn_timeout(unsigned long arg)
--{
-- struct l2cap_conn *conn = (void *)arg;
--
-- DBG("conn %p state %d", conn, conn->state);
--
-- if (conn->state == BT_CONNECTED) {
-- hci_disconnect(conn->hconn, 0x13);
-- }
--
-- return;
--}
--
--static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
--{
-- DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
--
-- mod_timer(&conn->timer, jiffies + timeout);
--}
--
--static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
--{
-- DBG("conn %p state %d", conn, conn->state);
--
-- del_timer(&conn->timer);
--}
--
--static void l2cap_conn_init_timer(struct l2cap_conn *conn)
--{
-- init_timer(&conn->timer);
-- conn->timer.function = l2cap_conn_timeout;
-- conn->timer.data = (unsigned long)conn;
--}
--
--/* -------- L2CAP connections --------- */
--/* Add new connection to the interface.
-- * Interface must be locked
-- */
--static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
--{
-- struct l2cap_conn *conn;
-- bdaddr_t *src = iff->bdaddr;
--
-- if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
-- return NULL;
--
-- memset(conn, 0, sizeof(struct l2cap_conn));
--
-- conn->state = BT_OPEN;
-- conn->iff = iff;
-- bacpy(&conn->src, src);
-- bacpy(&conn->dst, dst);
--
-- spin_lock_init(&conn->lock);
-- conn->chan_list.lock = RW_LOCK_UNLOCKED;
--
-- l2cap_conn_init_timer(conn);
--
-- __l2cap_conn_link(iff, conn);
--
-- DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
--
-- MOD_INC_USE_COUNT;
--
-- return conn;
--}
--
--/* Delete connection on the interface.
-- * Interface must be locked
-- */
--static int l2cap_conn_del(struct l2cap_conn *conn, int err)
--{
-- struct sock *sk;
--
-- DBG("conn %p, state %d, err %d", conn, conn->state, err);
--
-- l2cap_conn_clear_timer(conn);
-- __l2cap_conn_unlink(conn->iff, conn);
--
-- conn->state = BT_CLOSED;
--
-- if (conn->rx_skb)
-- kfree_skb(conn->rx_skb);
--
-- /* Kill channels */
-- while ((sk = conn->chan_list.head)) {
-- bh_lock_sock(sk);
-- l2cap_sock_clear_timer(sk);
-- l2cap_chan_del(sk, err);
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
-- }
--
-- kfree(conn);
--
-- MOD_DEC_USE_COUNT;
-- return 0;
--}
--
--static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
--{
-- struct list_head *p;
--
-- list_for_each(p, &iff->conn_list) {
-- struct l2cap_conn *c;
--
-- c = list_entry(p, struct l2cap_conn, list);
-- if (!bacmp(&c->dst, dst))
-- return c;
-- }
-- return NULL;
--}
--
--int l2cap_connect(struct sock *sk)
--{
-- bdaddr_t *src = &l2cap_pi(sk)->src;
-- bdaddr_t *dst = &l2cap_pi(sk)->dst;
-- struct l2cap_conn *conn;
-- struct l2cap_iff *iff;
-- int err = 0;
--
-- DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
--
-- read_lock_bh(&l2cap_rt_lock);
--
-- /* Get route to remote BD address */
-- if (!(iff = l2cap_get_route(src, dst))) {
-- err = -EHOSTUNREACH;
-- goto done;
-- }
--
-- /* Update source addr of the socket */
-- bacpy(src, iff->bdaddr);
--
-- l2cap_iff_lock(iff);
--
-- if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
-- /* Connection doesn't exist */
-- if (!(conn = l2cap_conn_add(iff, dst))) {
-- l2cap_iff_unlock(iff);
-- err = -ENOMEM;
-- goto done;
-- }
-- conn->out = 1;
-- }
--
-- l2cap_iff_unlock(iff);
--
-- l2cap_chan_add(conn, sk, NULL);
--
-- sk->state = BT_CONNECT;
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
--
-- switch (conn->state) {
-- case BT_CONNECTED:
-- if (sk->type == SOCK_SEQPACKET) {
-- l2cap_conn_req req;
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- req.psm = l2cap_pi(sk)->psm;
-- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-- } else {
-- l2cap_sock_clear_timer(sk);
-- sk->state = BT_CONNECTED;
-- }
-- break;
--
-- case BT_CONNECT:
-- break;
--
-- default:
-- /* Create ACL connection */
-- conn->state = BT_CONNECT;
-- hci_connect(iff->hdev, dst);
-- break;
-- };
--
--done:
-- read_unlock_bh(&l2cap_rt_lock);
-- return err;
--}
--
--/* ------ Channel queues for listening sockets ------ */
--void l2cap_accept_queue(struct sock *parent, struct sock *sk)
--{
-- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
--
-- DBG("parent %p, sk %p", parent, sk);
--
-- sock_hold(sk);
-- l2cap_pi(sk)->parent = parent;
-- l2cap_pi(sk)->next_q = NULL;
--
-- if (!q->head) {
-- q->head = q->tail = sk;
-- } else {
-- struct sock *tail = q->tail;
--
-- l2cap_pi(sk)->prev_q = tail;
-- l2cap_pi(tail)->next_q = sk;
-- q->tail = sk;
-- }
--
-- parent->ack_backlog++;
--}
--
--void l2cap_accept_unlink(struct sock *sk)
--{
-- struct sock *parent = l2cap_pi(sk)->parent;
-- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-- struct sock *next, *prev;
--
-- DBG("sk %p", sk);
--
-- next = l2cap_pi(sk)->next_q;
-- prev = l2cap_pi(sk)->prev_q;
--
-- if (sk == q->head)
-- q->head = next;
-- if (sk == q->tail)
-- q->tail = prev;
--
-- if (next)
-- l2cap_pi(next)->prev_q = prev;
-- if (prev)
-- l2cap_pi(prev)->next_q = next;
--
-- l2cap_pi(sk)->parent = NULL;
--
-- parent->ack_backlog--;
-- __sock_put(sk);
--}
--
--/* Get next connected channel in queue. */
--struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
--{
-- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-- struct sock *sk;
--
-- for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
-- if (!state || sk->state == state) {
-- l2cap_accept_unlink(sk);
-- break;
-- }
-- }
--
-- DBG("parent %p, sk %p", parent, sk);
--
-- return sk;
--}
--
--/* -------- Socket interface ---------- */
--static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
--{
-- bdaddr_t *src = &addr->l2_bdaddr;
-- __u16 psm = addr->l2_psm;
-- struct sock *sk;
--
-- for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-- if (l2cap_pi(sk)->psm == psm &&
-- !bacmp(&l2cap_pi(sk)->src, src))
-- break;
-- }
--
-- return sk;
--}
--
--/* Find socket listening on psm and source bdaddr.
-- * Returns closest match.
-- */
--static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
--{
-- struct sock *sk, *sk1 = NULL;
--
-- read_lock(&l2cap_sk_list.lock);
--
-- for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-- struct l2cap_pinfo *pi;
--
-- if (sk->state != BT_LISTEN)
-- continue;
--
-- pi = l2cap_pi(sk);
--
-- if (pi->psm == psm) {
-- /* Exact match. */
-- if (!bacmp(&pi->src, src))
-- break;
--
-- /* Closest match */
-- if (!bacmp(&pi->src, BDADDR_ANY))
-- sk1 = sk;
-- }
-- }
--
-- read_unlock(&l2cap_sk_list.lock);
--
-- return sk ? sk : sk1;
--}
--
--static void l2cap_sock_destruct(struct sock *sk)
--{
-- DBG("sk %p", sk);
--
-- skb_queue_purge(&sk->receive_queue);
-- skb_queue_purge(&sk->write_queue);
--
-- MOD_DEC_USE_COUNT;
--}
--
--static void l2cap_sock_cleanup_listen(struct sock *parent)
--{
-- struct sock *sk;
--
-- DBG("parent %p", parent);
--
-- /* Close not yet accepted channels */
-- while ((sk = l2cap_accept_dequeue(parent, 0)))
-- l2cap_sock_close(sk);
--
-- parent->state = BT_CLOSED;
-- parent->zapped = 1;
--}
--
--/* Kill socket (only if zapped and orphan)
-- * Must be called on unlocked socket.
-- */
--static void l2cap_sock_kill(struct sock *sk)
--{
-- if (!sk->zapped || sk->socket)
-- return;
--
-- DBG("sk %p state %d", sk, sk->state);
--
-- /* Kill poor orphan */
-- bluez_sock_unlink(&l2cap_sk_list, sk);
-- sk->dead = 1;
-- sock_put(sk);
--}
--
--/* Close socket.
-- * Must be called on unlocked socket.
-- */
--static void l2cap_sock_close(struct sock *sk)
--{
-- struct l2cap_conn *conn;
--
-- l2cap_sock_clear_timer(sk);
--
-- lock_sock(sk);
--
-- conn = l2cap_pi(sk)->conn;
--
-- DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
--
-- switch (sk->state) {
-- case BT_LISTEN:
-- l2cap_sock_cleanup_listen(sk);
-- break;
--
-- case BT_CONNECTED:
-- case BT_CONFIG:
-- if (sk->type == SOCK_SEQPACKET) {
-- l2cap_disconn_req req;
--
-- sk->state = BT_DISCONN;
--
-- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
--
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
-- } else {
-- l2cap_chan_del(sk, ECONNRESET);
-- }
-- break;
--
-- case BT_CONNECT:
-- case BT_DISCONN:
-- l2cap_chan_del(sk, ECONNRESET);
-- break;
--
-- default:
-- sk->zapped = 1;
-- break;
-- };
--
-- release_sock(sk);
--
-- l2cap_sock_kill(sk);
--}
--
--static void l2cap_sock_init(struct sock *sk, struct sock *parent)
--{
-- struct l2cap_pinfo *pi = l2cap_pi(sk);
--
-- DBG("sk %p", sk);
--
-- if (parent) {
-- sk->type = parent->type;
--
-- pi->imtu = l2cap_pi(parent)->imtu;
-- pi->omtu = l2cap_pi(parent)->omtu;
-- } else {
-- pi->imtu = L2CAP_DEFAULT_MTU;
-- pi->omtu = 0;
-- }
--
-- /* Default config options */
-- pi->conf_mtu = L2CAP_DEFAULT_MTU;
-- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
--}
--
--static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
--{
-- struct sock *sk;
--
-- if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-- return NULL;
--
-- sock_init_data(sock, sk);
--
-- sk->zapped = 0;
--
-- sk->destruct = l2cap_sock_destruct;
-- sk->sndtimeo = L2CAP_CONN_TIMEOUT;
--
-- sk->protocol = proto;
-- sk->state = BT_OPEN;
--
-- l2cap_sock_init_timer(sk);
--
-- bluez_sock_link(&l2cap_sk_list, sk);
--
-- MOD_INC_USE_COUNT;
--
-- return sk;
--}
--
--static int l2cap_sock_create(struct socket *sock, int protocol)
--{
-- struct sock *sk;
--
-- DBG("sock %p", sock);
--
-- sock->state = SS_UNCONNECTED;
--
-- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
-- return -ESOCKTNOSUPPORT;
--
-- sock->ops = &l2cap_sock_ops;
--
-- if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
-- return -ENOMEM;
--
-- l2cap_sock_init(sk, NULL);
--
-- return 0;
--}
--
--static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
--{
-- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
--
-- if (!addr || addr->sa_family != AF_BLUETOOTH)
-- return -EINVAL;
--
-- lock_sock(sk);
--
-- if (sk->state != BT_OPEN) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- write_lock(&l2cap_sk_list.lock);
--
-- if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
-- err = -EADDRINUSE;
-- goto unlock;
-- }
--
-- /* Save source address */
-- bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
-- l2cap_pi(sk)->psm = la->l2_psm;
-- sk->state = BT_BOUND;
--
--unlock:
-- write_unlock(&l2cap_sk_list.lock);
--
--done:
-- release_sock(sk);
--
-- return err;
--}
--
--static int l2cap_sock_w4_connect(struct sock *sk, int flags)
--{
-- DECLARE_WAITQUEUE(wait, current);
-- long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
-- int err = 0;
--
-- DBG("sk %p", sk);
--
-- add_wait_queue(sk->sleep, &wait);
-- current->state = TASK_INTERRUPTIBLE;
--
-- while (sk->state != BT_CONNECTED) {
-- if (!timeo) {
-- err = -EAGAIN;
-- break;
-- }
--
-- release_sock(sk);
-- timeo = schedule_timeout(timeo);
-- lock_sock(sk);
--
-- err = 0;
-- if (sk->state == BT_CONNECTED)
-- break;
--
-- if (sk->err) {
-- err = sock_error(sk);
-- break;
-- }
--
-- if (signal_pending(current)) {
-- err = sock_intr_errno(timeo);
-- break;
-- }
-- }
-- current->state = TASK_RUNNING;
-- remove_wait_queue(sk->sleep, &wait);
--
-- return err;
--}
--
--static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
--{
-- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- lock_sock(sk);
--
-- DBG("sk %p", sk);
--
-- if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-- err = -EINVAL;
-- goto done;
-- }
--
-- if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
-- err = -EINVAL;
-- goto done;
-- }
--
-- /* Set destination address and psm */
-- bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
-- l2cap_pi(sk)->psm = la->l2_psm;
--
-- if ((err = l2cap_connect(sk)))
-- goto done;
--
-- err = l2cap_sock_w4_connect(sk, flags);
--
--done:
-- release_sock(sk);
-- return err;
--}
--
--int l2cap_sock_listen(struct socket *sock, int backlog)
--{
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- DBG("sk %p backlog %d", sk, backlog);
--
-- lock_sock(sk);
--
-- if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- if (!l2cap_pi(sk)->psm) {
-- err = -EINVAL;
-- goto done;
-- }
--
-- sk->max_ack_backlog = backlog;
-- sk->ack_backlog = 0;
-- sk->state = BT_LISTEN;
--
--done:
-- release_sock(sk);
-- return err;
--}
--
--int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
--{
-- DECLARE_WAITQUEUE(wait, current);
-- struct sock *sk = sock->sk, *ch;
-- long timeo;
-- int err = 0;
--
-- lock_sock(sk);
--
-- if (sk->state != BT_LISTEN) {
-- err = -EBADFD;
-- goto done;
-- }
--
-- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
--
-- DBG("sk %p timeo %ld", sk, timeo);
--
-- /* Wait for an incoming connection. (wake-one). */
-- add_wait_queue_exclusive(sk->sleep, &wait);
-- current->state = TASK_INTERRUPTIBLE;
-- while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
-- if (!timeo) {
-- err = -EAGAIN;
-- break;
-- }
--
-- release_sock(sk);
-- timeo = schedule_timeout(timeo);
-- lock_sock(sk);
--
-- if (sk->state != BT_LISTEN) {
-- err = -EBADFD;
-- break;
-- }
--
-- if (signal_pending(current)) {
-- err = sock_intr_errno(timeo);
-- break;
-- }
-- }
-- current->state = TASK_RUNNING;
-- remove_wait_queue(sk->sleep, &wait);
--
-- if (err)
-- goto done;
--
-- sock_graft(ch, newsock);
-- newsock->state = SS_CONNECTED;
--
-- DBG("new socket %p", ch);
--
--done:
-- release_sock(sk);
--
-- return err;
--}
--
--static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
--{
-- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-- struct sock *sk = sock->sk;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- addr->sa_family = AF_BLUETOOTH;
-- *len = sizeof(struct sockaddr_l2);
--
-- if (peer)
-- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
-- else
-- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
--
-- la->l2_psm = l2cap_pi(sk)->psm;
--
-- return 0;
--}
--
--static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
--{
-- struct sock *sk = sock->sk;
-- int err = 0;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- if (sk->err)
-- return sock_error(sk);
--
-- if (msg->msg_flags & MSG_OOB)
-- return -EOPNOTSUPP;
--
-- lock_sock(sk);
--
-- if (sk->state == BT_CONNECTED)
-- err = l2cap_chan_send(sk, msg, len);
-- else
-- err = -ENOTCONN;
--
-- release_sock(sk);
-- return err;
--}
--
--static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
--{
-- struct sock *sk = sock->sk;
-- int noblock = flags & MSG_DONTWAIT;
-- int copied, err;
-- struct sk_buff *skb;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- if (flags & (MSG_OOB))
-- return -EOPNOTSUPP;
--
-- if (sk->state == BT_CLOSED)
-- return 0;
--
-- if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
-- return err;
--
-- msg->msg_namelen = 0;
--
-- copied = skb->len;
-- if (len < copied) {
-- msg->msg_flags |= MSG_TRUNC;
-- copied = len;
-- }
--
-- skb->h.raw = skb->data;
-- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
--
-- skb_free_datagram(sk, skb);
--
-- return err ? : copied;
--}
--
--int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
--{
-- struct sock *sk = sock->sk;
-- struct l2cap_options opts;
-- int err = 0;
--
-- DBG("sk %p", sk);
--
-- lock_sock(sk);
--
-- switch (optname) {
-- case L2CAP_OPTIONS:
-- if (copy_from_user((char *)&opts, optval, optlen)) {
-- err = -EFAULT;
-- break;
-- }
-- l2cap_pi(sk)->imtu = opts.imtu;
-- l2cap_pi(sk)->omtu = opts.omtu;
-- break;
--
-- default:
-- err = -ENOPROTOOPT;
-- break;
-- };
--
-- release_sock(sk);
-- return err;
--}
--
--int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
--{
-- struct sock *sk = sock->sk;
-- struct l2cap_options opts;
-- struct l2cap_conninfo cinfo;
-- int len, err = 0;
--
-- if (get_user(len, optlen))
-- return -EFAULT;
--
-- lock_sock(sk);
--
-- switch (optname) {
-- case L2CAP_OPTIONS:
-- opts.imtu = l2cap_pi(sk)->imtu;
-- opts.omtu = l2cap_pi(sk)->omtu;
-- opts.flush_to = l2cap_pi(sk)->flush_to;
--
-- len = MIN(len, sizeof(opts));
-- if (copy_to_user(optval, (char *)&opts, len))
-- err = -EFAULT;
--
-- break;
--
-- case L2CAP_CONNINFO:
-- if (sk->state != BT_CONNECTED) {
-- err = -ENOTCONN;
-- break;
-- }
--
-- cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
--
-- len = MIN(len, sizeof(cinfo));
-- if (copy_to_user(optval, (char *)&cinfo, len))
-- err = -EFAULT;
--
-- break;
--
-- default:
-- err = -ENOPROTOOPT;
-- break;
-- };
--
-- release_sock(sk);
-- return err;
--}
--
--static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
--{
-- struct sock *sk = sock->sk;
-- struct l2cap_accept_q *aq;
-- unsigned int mask;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- poll_wait(file, sk->sleep, wait);
-- mask = 0;
--
-- if (sk->err || !skb_queue_empty(&sk->error_queue))
-- mask |= POLLERR;
--
-- if (sk->shutdown == SHUTDOWN_MASK)
-- mask |= POLLHUP;
--
-- aq = &l2cap_pi(sk)->accept_q;
-- if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
-- mask |= POLLIN | POLLRDNORM;
--
-- if (sk->state == BT_CLOSED)
-- mask |= POLLHUP;
--
-- if (sock_writeable(sk))
-- mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-- else
-- set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
--
-- return mask;
--}
--
--static int l2cap_sock_release(struct socket *sock)
--{
-- struct sock *sk = sock->sk;
--
-- DBG("sock %p, sk %p", sock, sk);
--
-- if (!sk)
-- return 0;
--
-- sock_orphan(sk);
--
-- l2cap_sock_close(sk);
--
-- return 0;
--}
--
--/* --------- L2CAP channels --------- */
--static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-- if (l2cap_pi(s)->dcid == cid)
-- break;
-- }
--
-- return s;
--}
--
--static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- read_lock(&l->lock);
-- s = __l2cap_get_chan_by_dcid(l, cid);
-- read_unlock(&l->lock);
--
-- return s;
--}
--
--static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-- if (l2cap_pi(s)->scid == cid)
-- break;
-- }
--
-- return s;
--}
--static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
--{
-- struct sock *s;
--
-- read_lock(&l->lock);
-- s = __l2cap_get_chan_by_scid(l, cid);
-- read_unlock(&l->lock);
--
-- return s;
--}
--
--static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
--{
-- struct sock *s;
--
-- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-- if (l2cap_pi(s)->ident == ident)
-- break;
-- }
--
-- return s;
--}
--
--static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
--{
-- struct sock *s;
--
-- read_lock(&l->lock);
-- s = __l2cap_get_chan_by_ident(l, ident);
-- read_unlock(&l->lock);
--
-- return s;
--}
--
--static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
--{
-- __u16 cid = 0x0040;
--
-- for (; cid < 0xffff; cid++) {
-- if(!__l2cap_get_chan_by_scid(l, cid))
-- return cid;
-- }
--
-- return 0;
--}
--
--static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
--{
-- sock_hold(sk);
--
-- if (l->head)
-- l2cap_pi(l->head)->prev_c = sk;
--
-- l2cap_pi(sk)->next_c = l->head;
-- l2cap_pi(sk)->prev_c = NULL;
-- l->head = sk;
--}
--
--static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
--{
-- struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
--
-- write_lock(&l->lock);
-- if (sk == l->head)
-- l->head = next;
--
-- if (next)
-- l2cap_pi(next)->prev_c = prev;
-- if (prev)
-- l2cap_pi(prev)->next_c = next;
-- write_unlock(&l->lock);
--
-- __sock_put(sk);
--}
--
--static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
--
-- DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
--
-- l2cap_conn_clear_timer(conn);
--
-- atomic_inc(&conn->refcnt);
-- l2cap_pi(sk)->conn = conn;
--
-- if (sk->type == SOCK_SEQPACKET) {
-- /* Alloc CID for normal socket */
-- l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
-- } else {
-- /* Raw socket can send only signalling messages */
-- l2cap_pi(sk)->scid = 0x0001;
-- l2cap_pi(sk)->dcid = 0x0001;
-- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-- }
--
-- __l2cap_chan_link(l, sk);
--
-- if (parent)
-- l2cap_accept_queue(parent, sk);
--}
--
--static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
--
-- write_lock(&l->lock);
-- __l2cap_chan_add(conn, sk, parent);
-- write_unlock(&l->lock);
--}
--
--/* Delete channel.
-- * Must be called on the locked socket. */
--static void l2cap_chan_del(struct sock *sk, int err)
--{
-- struct l2cap_conn *conn;
-- struct sock *parent;
--
-- conn = l2cap_pi(sk)->conn;
-- parent = l2cap_pi(sk)->parent;
--
-- DBG("sk %p, conn %p, err %d", sk, conn, err);
--
-- if (parent) {
-- /* Unlink from parent accept queue */
-- bh_lock_sock(parent);
-- l2cap_accept_unlink(sk);
-- bh_unlock_sock(parent);
-- }
--
-- if (conn) {
-- long timeout;
--
-- /* Unlink from channel list */
-- l2cap_chan_unlink(&conn->chan_list, sk);
-- l2cap_pi(sk)->conn = NULL;
--
-- if (conn->out)
-- timeout = L2CAP_DISCONN_TIMEOUT;
-- else
-- timeout = L2CAP_CONN_IDLE_TIMEOUT;
--
-- if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
-- /* Schedule Baseband disconnect */
-- l2cap_conn_set_timer(conn, timeout);
-- }
-- }
--
-- sk->state = BT_CLOSED;
-- sk->err = err;
-- sk->state_change(sk);
--
-- sk->zapped = 1;
--}
--
--static void l2cap_conn_ready(struct l2cap_conn *conn)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
-- struct sock *sk;
--
-- DBG("conn %p", conn);
--
-- read_lock(&l->lock);
--
-- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-- bh_lock_sock(sk);
--
-- if (sk->type != SOCK_SEQPACKET) {
-- sk->state = BT_CONNECTED;
-- sk->state_change(sk);
-- l2cap_sock_clear_timer(sk);
-- } else if (sk->state == BT_CONNECT) {
-- l2cap_conn_req req;
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- req.psm = l2cap_pi(sk)->psm;
-- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
--
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
-- }
--
-- bh_unlock_sock(sk);
-- }
--
-- read_unlock(&l->lock);
--}
--
--static void l2cap_chan_ready(struct sock *sk)
--{
-- struct sock *parent = l2cap_pi(sk)->parent;
--
-- DBG("sk %p, parent %p", sk, parent);
--
-- l2cap_pi(sk)->conf_state = 0;
-- l2cap_sock_clear_timer(sk);
--
-- if (!parent) {
-- /* Outgoing channel.
-- * Wake up socket sleeping on connect.
-- */
-- sk->state = BT_CONNECTED;
-- sk->state_change(sk);
-- } else {
-- /* Incomming channel.
-- * Wake up socket sleeping on accept.
-- */
-- parent->data_ready(parent, 1);
-- }
--}
--
--/* Copy frame to all raw sockets on that connection */
--void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
--{
-- struct l2cap_chan_list *l = &conn->chan_list;
-- struct sk_buff *nskb;
-- struct sock * sk;
--
-- DBG("conn %p", conn);
--
-- read_lock(&l->lock);
-- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-- if (sk->type != SOCK_RAW)
-- continue;
--
-- /* Don't send frame to the socket it came from */
-- if (skb->sk == sk)
-- continue;
--
-- if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
-- continue;
--
-- skb_queue_tail(&sk->receive_queue, nskb);
-- sk->data_ready(sk, nskb->len);
-- }
-- read_unlock(&l->lock);
--}
--
--static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
--{
-- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-- struct sk_buff *skb, **frag;
-- int err, size, count, sent=0;
-- l2cap_hdr *lh;
--
-- /* Check outgoing MTU */
-- if (len > l2cap_pi(sk)->omtu)
-- return -EINVAL;
--
-- DBG("sk %p len %d", sk, len);
--
-- /* First fragment (with L2CAP header) */
-- count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
-- size = L2CAP_HDR_SIZE + count;
-- if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
-- return err;
--
-- /* Create L2CAP header */
-- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-- lh->len = __cpu_to_le16(len);
-- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
--
-- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-- err = -EFAULT;
-- goto fail;
-- }
--
-- sent += count;
-- len -= count;
--
-- /* Continuation fragments (no L2CAP header) */
-- frag = &skb_shinfo(skb)->frag_list;
-- while (len) {
-- count = MIN(conn->iff->mtu, len);
--
-- *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
-- if (!*frag)
-- goto fail;
--
-- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
-- err = -EFAULT;
-- goto fail;
-- }
--
-- sent += count;
-- len -= count;
--
-- frag = &(*frag)->next;
-- }
--
-- if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
-- goto fail;
--
-- return sent;
--
--fail:
-- kfree_skb(skb);
-- return err;
--}
--
--/* --------- L2CAP signalling commands --------- */
--static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
--{
-- __u8 id;
--
-- /* Get next available identificator.
-- * 1 - 199 are used by kernel.
-- * 200 - 254 are used by utilities like l2ping, etc
-- */
--
-- spin_lock(&conn->lock);
--
-- if (++conn->tx_ident > 199)
-- conn->tx_ident = 1;
--
-- id = conn->tx_ident;
--
-- spin_unlock(&conn->lock);
--
-- return id;
--}
--
--static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
--{
-- struct sk_buff *skb;
-- l2cap_cmd_hdr *cmd;
-- l2cap_hdr *lh;
-- int size;
--
-- DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
--
-- size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
-- if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
-- return NULL;
--
-- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-- lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
-- lh->cid = __cpu_to_le16(0x0001);
--
-- cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
-- cmd->code = code;
-- cmd->ident = ident;
-- cmd->len = __cpu_to_le16(len);
--
-- if (len)
-- memcpy(skb_put(skb, len), data, len);
--
-- return skb;
--}
--
--static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
--{
-- struct sk_buff *skb;
-- __u8 ident;
--
-- DBG("code 0x%2.2x", code);
--
-- ident = l2cap_get_ident(conn);
-- if (!(skb = l2cap_build_cmd(code, ident, len, data)))
-- return -ENOMEM;
-- return hci_send_acl(conn->hconn, skb, 0);
--}
--
--static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
--{
-- struct sk_buff *skb;
--
-- DBG("code 0x%2.2x", code);
--
-- if (!(skb = l2cap_build_cmd(code, ident, len, data)))
-- return -ENOMEM;
-- return hci_send_acl(conn->hconn, skb, 0);
--}
--
--static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
--{
-- l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
-- int len;
--
-- *type = opt->type;
-- switch (opt->len) {
-- case 1:
-- *val = *((__u8 *) opt->val);
-- break;
--
-- case 2:
-- *val = __le16_to_cpu(*((__u16 *)opt->val));
-- break;
--
-- case 4:
-- *val = __le32_to_cpu(*((__u32 *)opt->val));
-- break;
--
-- default:
-- *val = 0L;
-- break;
-- };
--
-- DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
--
-- len = L2CAP_CONF_OPT_SIZE + opt->len;
--
-- *ptr += len;
--
-- return len;
--}
--
--static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
--{
-- __u8 type, hint; __u32 val;
-- __u8 *ptr = data;
--
-- DBG("sk %p len %d", sk, len);
--
-- while (len >= L2CAP_CONF_OPT_SIZE) {
-- len -= l2cap_get_conf_opt(&ptr, &type, &val);
--
-- hint = type & 0x80;
-- type &= 0x7f;
--
-- switch (type) {
-- case L2CAP_CONF_MTU:
-- l2cap_pi(sk)->conf_mtu = val;
-- break;
--
-- case L2CAP_CONF_FLUSH_TO:
-- l2cap_pi(sk)->flush_to = val;
-- break;
--
-- case L2CAP_CONF_QOS:
-- break;
--
-- default:
-- if (hint)
-- break;
--
-- /* FIXME: Reject unknon option */
-- break;
-- };
-- }
--}
--
--static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
--{
-- register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
--
-- DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
--
-- opt->type = type;
-- opt->len = len;
-- switch (len) {
-- case 1:
-- *((__u8 *) opt->val) = val;
-- break;
--
-- case 2:
-- *((__u16 *) opt->val) = __cpu_to_le16(val);
-- break;
--
-- case 4:
-- *((__u32 *) opt->val) = __cpu_to_le32(val);
-- break;
-- };
--
-- *ptr += L2CAP_CONF_OPT_SIZE + len;
--}
--
--static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
--{
-- struct l2cap_pinfo *pi = l2cap_pi(sk);
-- l2cap_conf_req *req = (l2cap_conf_req *) data;
-- __u8 *ptr = req->data;
--
-- DBG("sk %p", sk);
--
-- if (pi->imtu != L2CAP_DEFAULT_MTU)
-- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
--
-- /* FIXME. Need actual value of the flush timeout */
-- //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-- // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
--
-- req->dcid = __cpu_to_le16(pi->dcid);
-- req->flags = __cpu_to_le16(0);
--
-- return ptr - data;
--}
--
--static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
--{
-- struct l2cap_pinfo *pi = l2cap_pi(sk);
-- int result = 0;
--
-- /* Configure output options and let other side know
-- * which ones we don't like.
-- */
-- if (pi->conf_mtu < pi->omtu) {
-- l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
-- result = L2CAP_CONF_UNACCEPT;
-- } else {
-- pi->omtu = pi->conf_mtu;
-- }
--
-- DBG("sk %p result %d", sk, result);
-- return result;
--}
--
--static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
--{
-- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
-- __u8 *ptr = rsp->data;
--
-- DBG("sk %p complete %d", sk, result ? 1 : 0);
--
-- if (result)
-- *result = l2cap_conf_output(sk, &ptr);
--
-- rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- rsp->result = __cpu_to_le16(result ? *result : 0);
-- rsp->flags = __cpu_to_le16(0);
--
-- return ptr - data;
--}
--
--static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- struct l2cap_chan_list *list = &conn->chan_list;
-- l2cap_conn_req *req = (l2cap_conn_req *) data;
-- l2cap_conn_rsp rsp;
-- struct sock *sk, *parent;
--
-- __u16 scid = __le16_to_cpu(req->scid);
-- __u16 psm = req->psm;
--
-- DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
--
-- /* Check if we have socket listening on psm */
-- if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
-- goto reject;
--
-- bh_lock_sock(parent);
-- write_lock(&list->lock);
--
-- /* Check if we already have channel with that dcid */
-- if (__l2cap_get_chan_by_dcid(list, scid))
-- goto unlock;
--
-- /* Check for backlog size */
-- if (parent->ack_backlog > parent->max_ack_backlog)
-- goto unlock;
--
-- if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
-- goto unlock;
--
-- l2cap_sock_init(sk, parent);
--
-- bacpy(&l2cap_pi(sk)->src, &conn->src);
-- bacpy(&l2cap_pi(sk)->dst, &conn->dst);
-- l2cap_pi(sk)->psm = psm;
-- l2cap_pi(sk)->dcid = scid;
--
-- __l2cap_chan_add(conn, sk, parent);
-- sk->state = BT_CONFIG;
--
-- write_unlock(&list->lock);
-- bh_unlock_sock(parent);
--
-- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- rsp.result = __cpu_to_le16(0);
-- rsp.status = __cpu_to_le16(0);
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
--
-- return 0;
--
--unlock:
-- write_unlock(&list->lock);
-- bh_unlock_sock(parent);
--
--reject:
-- rsp.scid = __cpu_to_le16(scid);
-- rsp.dcid = __cpu_to_le16(0);
-- rsp.status = __cpu_to_le16(0);
-- rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
--
-- return 0;
--}
--
--static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
-- __u16 scid, dcid, result, status;
-- struct sock *sk;
--
-- scid = __le16_to_cpu(rsp->scid);
-- dcid = __le16_to_cpu(rsp->dcid);
-- result = __le16_to_cpu(rsp->result);
-- status = __le16_to_cpu(rsp->status);
--
-- DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
--
-- if (!result) {
-- char req[64];
--
-- sk->state = BT_CONFIG;
-- l2cap_pi(sk)->dcid = dcid;
-- l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
--
-- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-- } else {
-- l2cap_chan_del(sk, ECONNREFUSED);
-- }
--
-- bh_unlock_sock(sk);
-- return 0;
--}
--
--static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_conf_req * req = (l2cap_conf_req *) data;
-- __u16 dcid, flags;
-- __u8 rsp[64];
-- struct sock *sk;
-- int result;
--
-- dcid = __le16_to_cpu(req->dcid);
-- flags = __le16_to_cpu(req->flags);
--
-- DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
--
-- l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
--
-- if (flags & 0x01) {
-- /* Incomplete config. Send empty response. */
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
-- goto unlock;
-- }
--
-- /* Complete config. */
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
--
-- if (result)
-- goto unlock;
--
-- /* Output config done */
-- l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
--
-- if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
-- sk->state = BT_CONNECTED;
-- l2cap_chan_ready(sk);
-- } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
-- char req[64];
-- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-- }
--
--unlock:
-- bh_unlock_sock(sk);
--
-- return 0;
--}
--
--static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
-- __u16 scid, flags, result;
-- struct sock *sk;
-- int err = 0;
--
-- scid = __le16_to_cpu(rsp->scid);
-- flags = __le16_to_cpu(rsp->flags);
-- result = __le16_to_cpu(rsp->result);
--
-- DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
--
-- if (result) {
-- l2cap_disconn_req req;
--
-- /* They didn't like our options. Well... we do not negotiate.
-- * Close channel.
-- */
-- sk->state = BT_DISCONN;
--
-- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
--
-- l2cap_sock_set_timer(sk, sk->sndtimeo);
-- goto done;
-- }
--
-- if (flags & 0x01)
-- goto done;
--
-- /* Input config done */
-- l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
--
-- if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
-- sk->state = BT_CONNECTED;
-- l2cap_chan_ready(sk);
-- }
--
--done:
-- bh_unlock_sock(sk);
--
-- return err;
--}
--
--static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_disconn_req *req = (l2cap_disconn_req *) data;
-- l2cap_disconn_rsp rsp;
-- __u16 dcid, scid;
-- struct sock *sk;
--
-- scid = __le16_to_cpu(req->scid);
-- dcid = __le16_to_cpu(req->dcid);
--
-- DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-- return 0;
--
-- bh_lock_sock(sk);
--
-- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-- l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
--
-- l2cap_chan_del(sk, ECONNRESET);
--
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
--
-- return 0;
--}
--
--static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
-- l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
-- __u16 dcid, scid;
-- struct sock *sk;
--
-- scid = __le16_to_cpu(rsp->scid);
-- dcid = __le16_to_cpu(rsp->dcid);
--
-- DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-- return -ENOENT;
--
-- bh_lock_sock(sk);
-- l2cap_sock_clear_timer(sk);
-- l2cap_chan_del(sk, ECONNABORTED);
-- bh_unlock_sock(sk);
--
-- l2cap_sock_kill(sk);
--
-- return 0;
--}
--
--static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
--{
-- __u8 *data = skb->data;
-- int len = skb->len;
-- l2cap_cmd_hdr cmd;
-- int err = 0;
--
-- while (len >= L2CAP_CMD_HDR_SIZE) {
-- memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-- data += L2CAP_CMD_HDR_SIZE;
-- len -= L2CAP_CMD_HDR_SIZE;
--
-- cmd.len = __le16_to_cpu(cmd.len);
--
-- DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
--
-- if (cmd.len > len || !cmd.ident) {
-- DBG("corrupted command");
-- break;
-- }
--
-- switch (cmd.code) {
-- case L2CAP_CONN_REQ:
-- err = l2cap_connect_req(conn, &cmd, data);
-- break;
--
-- case L2CAP_CONN_RSP:
-- err = l2cap_connect_rsp(conn, &cmd, data);
-- break;
--
-- case L2CAP_CONF_REQ:
-- err = l2cap_config_req(conn, &cmd, data);
-- break;
--
-- case L2CAP_CONF_RSP:
-- err = l2cap_config_rsp(conn, &cmd, data);
-- break;
--
-- case L2CAP_DISCONN_REQ:
-- err = l2cap_disconnect_req(conn, &cmd, data);
-- break;
--
-- case L2CAP_DISCONN_RSP:
-- err = l2cap_disconnect_rsp(conn, &cmd, data);
-- break;
--
-- case L2CAP_COMMAND_REJ:
-- /* FIXME: We should process this */
-- l2cap_raw_recv(conn, skb);
-- break;
--
-- case L2CAP_ECHO_REQ:
-- l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
-- break;
--
-- case L2CAP_ECHO_RSP:
-- case L2CAP_INFO_REQ:
-- case L2CAP_INFO_RSP:
-- l2cap_raw_recv(conn, skb);
-- break;
--
-- default:
-- ERR("Uknown signaling command 0x%2.2x", cmd.code);
-- err = -EINVAL;
-- break;
-- };
--
-- if (err) {
-- l2cap_cmd_rej rej;
-- DBG("error %d", err);
--
-- /* FIXME: Map err to a valid reason. */
-- rej.reason = __cpu_to_le16(0);
-- l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
-- }
--
-- data += cmd.len;
-- len -= cmd.len;
-- }
--
-- kfree_skb(skb);
--}
--
--static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
--{
-- struct sock *sk;
--
-- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
-- DBG("unknown cid 0x%4.4x", cid);
-- goto drop;
-- }
--
-- DBG("sk %p, len %d", sk, skb->len);
--
-- if (sk->state != BT_CONNECTED)
-- goto drop;
--
-- if (l2cap_pi(sk)->imtu < skb->len)
-- goto drop;
--
-- skb_queue_tail(&sk->receive_queue, skb);
-- sk->data_ready(sk, skb->len);
--
-- return 0;
--
--drop:
-- kfree_skb(skb);
--
-- return 0;
--}
--
--static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
--{
-- l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-- __u16 cid, len;
--
-- skb_pull(skb, L2CAP_HDR_SIZE);
-- cid = __le16_to_cpu(lh->cid);
-- len = __le16_to_cpu(lh->len);
--
-- DBG("len %d, cid 0x%4.4x", len, cid);
--
-- if (cid == 0x0001)
-- l2cap_sig_channel(conn, skb);
-- else
-- l2cap_data_channel(conn, cid, skb);
--}
--
--/* ------------ L2CAP interface with lower layer (HCI) ------------- */
--static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
--{
-- struct hci_dev *hdev = (struct hci_dev *) ptr;
--
-- DBG("hdev %s, event %ld", hdev->name, event);
--
-- write_lock(&l2cap_rt_lock);
--
-- switch (event) {
-- case HCI_DEV_UP:
-- l2cap_iff_add(hdev);
-- break;
--
-- case HCI_DEV_DOWN:
-- l2cap_iff_del(hdev);
-- break;
-- };
--
-- write_unlock(&l2cap_rt_lock);
--
-- return NOTIFY_DONE;
--}
--
--int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
--{
-- struct l2cap_iff *iff;
--
-- DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
--
-- if (!(iff = hdev->l2cap_data)) {
-- ERR("unknown interface");
-- return 0;
-- }
--
-- /* Always accept connection */
-- return 1;
--}
--
--int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
--{
-- struct l2cap_conn *conn;
-- struct l2cap_iff *iff;
-- int err = 0;
--
-- DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
--
-- if (!(iff = hdev->l2cap_data)) {
-- ERR("unknown interface");
-- return 0;
-- }
--
-- l2cap_iff_lock(iff);
--
-- conn = l2cap_get_conn_by_addr(iff, bdaddr);
--
-- if (conn) {
-- /* Outgoing connection */
-- DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
--
-- if (!status && hconn) {
-- conn->state = BT_CONNECTED;
-- conn->hconn = hconn;
--
-- hconn->l2cap_data = (void *)conn;
--
-- /* Establish channels */
-- l2cap_conn_ready(conn);
-- } else {
-- l2cap_conn_del(conn, bterr(status));
-- }
-- } else {
-- /* Incomming connection */
-- DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
--
-- if (status || !hconn)
-- goto done;
--
-- if (!(conn = l2cap_conn_add(iff, bdaddr))) {
-- err = -ENOMEM;
-- goto done;
-- }
--
-- conn->hconn = hconn;
-- hconn->l2cap_data = (void *)conn;
--
-- conn->state = BT_CONNECTED;
-- }
--
--done:
-- l2cap_iff_unlock(iff);
--
-- return err;
--}
--
--int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
--{
-- struct l2cap_conn *conn = hconn->l2cap_data;
--
-- DBG("hconn %p reason %d", hconn, reason);
--
-- if (!conn) {
-- ERR("unknown connection");
-- return 0;
-- }
-- conn->hconn = NULL;
--
-- l2cap_iff_lock(conn->iff);
-- l2cap_conn_del(conn, bterr(reason));
-- l2cap_iff_unlock(conn->iff);
--
-- return 0;
--}
--
--int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
--{
-- struct l2cap_conn *conn = hconn->l2cap_data;
--
-- if (!conn) {
-- ERR("unknown connection %p", hconn);
-- goto drop;
-- }
--
-- DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
--
-- if (flags & ACL_START) {
-- int flen, tlen, size;
-- l2cap_hdr *lh;
--
-- if (conn->rx_len) {
-- ERR("Unexpected start frame (len %d)", skb->len);
-- kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
-- conn->rx_len = 0;
-- }
--
-- if (skb->len < L2CAP_HDR_SIZE) {
-- ERR("Frame is too small (len %d)", skb->len);
-- goto drop;
-- }
--
-- lh = (l2cap_hdr *)skb->data;
-- tlen = __le16_to_cpu(lh->len);
-- flen = skb->len - L2CAP_HDR_SIZE;
--
-- DBG("Start: total len %d, frag len %d", tlen, flen);
--
-- if (flen == tlen) {
-- /* Complete frame received */
-- l2cap_recv_frame(conn, skb);
-- return 0;
-- }
--
-- /* Allocate skb for the complete frame (with header) */
-- size = L2CAP_HDR_SIZE + tlen;
-- if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
-- goto drop;
--
-- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
--
-- conn->rx_len = tlen - flen;
-- } else {
-- DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
--
-- if (!conn->rx_len) {
-- ERR("Unexpected continuation frame (len %d)", skb->len);
-- goto drop;
-- }
--
-- if (skb->len > conn->rx_len) {
-- ERR("Fragment is too large (len %d)", skb->len);
-- kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
-- goto drop;
-- }
--
-- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-- conn->rx_len -= skb->len;
--
-- if (!conn->rx_len) {
-- /* Complete frame received */
-- l2cap_recv_frame(conn, conn->rx_skb);
-- conn->rx_skb = NULL;
-- }
-- }
--
--drop:
-- kfree_skb(skb);
-- return 0;
--}
--
--struct proto_ops l2cap_sock_ops = {
-- family: PF_BLUETOOTH,
-- release: l2cap_sock_release,
-- bind: l2cap_sock_bind,
-- connect: l2cap_sock_connect,
-- listen: l2cap_sock_listen,
-- accept: l2cap_sock_accept,
-- getname: l2cap_sock_getname,
-- sendmsg: l2cap_sock_sendmsg,
-- recvmsg: l2cap_sock_recvmsg,
-- poll: l2cap_sock_poll,
-- socketpair: sock_no_socketpair,
-- ioctl: sock_no_ioctl,
-- shutdown: sock_no_shutdown,
-- setsockopt: l2cap_sock_setsockopt,
-- getsockopt: l2cap_sock_getsockopt,
-- mmap: sock_no_mmap
--};
--
--struct net_proto_family l2cap_sock_family_ops = {
-- family: PF_BLUETOOTH,
-- create: l2cap_sock_create
--};
--
--struct hci_proto l2cap_hci_proto = {
-- name: "L2CAP",
-- id: HCI_PROTO_L2CAP,
-- connect_ind: l2cap_connect_ind,
-- connect_cfm: l2cap_connect_cfm,
-- disconn_ind: l2cap_disconn_ind,
-- recv_acldata: l2cap_recv_acldata,
--};
--
--struct notifier_block l2cap_nblock = {
-- notifier_call: l2cap_dev_event
--};
--
--int __init l2cap_init(void)
--{
-- INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-- VERSION);
-- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
--
-- if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
-- ERR("Can't register L2CAP socket");
-- return -EPROTO;
-- }
--
-- if (hci_register_proto(&l2cap_hci_proto) < 0) {
-- ERR("Can't register L2CAP protocol");
-- return -EPROTO;
-- }
--
-- hci_register_notifier(&l2cap_nblock);
--
-- l2cap_register_proc();
--
-- return 0;
--}
--
--void l2cap_cleanup(void)
--{
-- l2cap_unregister_proc();
--
-- /* Unregister socket, protocol and notifier */
-- if (bluez_sock_unregister(BTPROTO_L2CAP))
-- ERR("Can't unregister L2CAP socket");
--
-- if (hci_unregister_proto(&l2cap_hci_proto) < 0)
-- ERR("Can't unregister L2CAP protocol");
--
-- hci_unregister_notifier(&l2cap_nblock);
--
-- /* We _must_ not have any sockets and/or connections
-- * at this stage.
-- */
--
-- /* Free interface list and unlock HCI devices */
-- {
-- struct list_head *list = &l2cap_iff_list;
--
-- while (!list_empty(list)) {
-- struct l2cap_iff *iff;
--
-- iff = list_entry(list->next, struct l2cap_iff, list);
-- l2cap_iff_del(iff->hdev);
-- }
-- }
--}
--
--module_init(l2cap_init);
--module_exit(l2cap_cleanup);
--
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
--MODULE_LICENSE("GPL");
--
-diff -urN linux-2.4.18/net/bluetooth/l2cap_proc.c linux-2.4.18-mh9/net/bluetooth/l2cap_proc.c
---- linux-2.4.18/net/bluetooth/l2cap_proc.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/net/bluetooth/l2cap_proc.c Thu Jan 1 01:00:00 1970
-@@ -1,165 +0,0 @@
--/*
-- BlueZ - Bluetooth protocol stack for Linux
-- Copyright (C) 2000-2001 Qualcomm Incorporated
--
-- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2 as
-- published by the Free Software Foundation;
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-- SOFTWARE IS DISCLAIMED.
--*/
--
--/*
-- * BlueZ L2CAP proc fs support.
-- *
-- * $Id$
-- */
--
--#include <linux/config.h>
--#include <linux/module.h>
--
--#include <linux/types.h>
--#include <linux/errno.h>
--#include <linux/kernel.h>
--#include <linux/major.h>
--#include <linux/sched.h>
--#include <linux/slab.h>
--#include <linux/poll.h>
--#include <linux/fcntl.h>
--#include <linux/init.h>
--#include <linux/skbuff.h>
--#include <linux/interrupt.h>
--#include <linux/socket.h>
--#include <linux/skbuff.h>
--#include <linux/proc_fs.h>
--#include <linux/list.h>
--#include <net/sock.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/l2cap_core.h>
--
--#ifndef L2CAP_DEBUG
--#undef DBG
--#define DBG( A... )
--#endif
--
--/* ----- PROC fs support ----- */
--static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
--{
-- struct list_head *p;
-- char *ptr = buf;
--
-- list_for_each(p, &iff->conn_list) {
-- struct l2cap_conn *c;
--
-- c = list_entry(p, struct l2cap_conn, list);
-- ptr += sprintf(ptr, " %p %d %p %p %s %s\n",
-- c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
-- }
--
-- return ptr - buf;
--}
--
--static int l2cap_iff_dump(char *buf)
--{
-- struct list_head *p;
-- char *ptr = buf;
--
-- ptr += sprintf(ptr, "Interfaces:\n");
--
-- write_lock(&l2cap_rt_lock);
--
-- list_for_each(p, &l2cap_iff_list) {
-- struct l2cap_iff *iff;
--
-- iff = list_entry(p, struct l2cap_iff, list);
--
-- ptr += sprintf(ptr, " %s %p %p\n", iff->hdev->name, iff, iff->hdev);
--
-- l2cap_iff_lock(iff);
-- ptr += l2cap_conn_dump(ptr, iff);
-- l2cap_iff_unlock(iff);
-- }
--
-- write_unlock(&l2cap_rt_lock);
--
-- ptr += sprintf(ptr, "\n");
--
-- return ptr - buf;
--}
--
--static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
--{
-- struct l2cap_pinfo *pi;
-- struct sock *sk;
-- char *ptr = buf;
--
-- ptr += sprintf(ptr, "Sockets:\n");
--
-- write_lock(&list->lock);
--
-- for (sk = list->head; sk; sk = sk->next) {
-- pi = l2cap_pi(sk);
-- ptr += sprintf(ptr, " %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
-- batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
-- }
--
-- write_unlock(&list->lock);
--
-- ptr += sprintf(ptr, "\n");
--
-- return ptr - buf;
--}
--
--static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
--{
-- char *ptr = buf;
-- int len;
--
-- DBG("count %d, offset %ld", count, offset);
--
-- ptr += l2cap_iff_dump(ptr);
-- ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
-- len = ptr - buf;
--
-- if (len <= count + offset)
-- *eof = 1;
--
-- *start = buf + offset;
-- len -= offset;
--
-- if (len > count)
-- len = count;
-- if (len < 0)
-- len = 0;
--
-- return len;
--}
--
--void l2cap_register_proc(void)
--{
-- create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
--}
--
--void l2cap_unregister_proc(void)
--{
-- remove_proc_entry("bluetooth/l2cap", NULL);
--}
-diff -urN linux-2.4.18/net/bluetooth/lib.c linux-2.4.18-mh9/net/bluetooth/lib.c
---- linux-2.4.18/net/bluetooth/lib.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/net/bluetooth/lib.c Mon Aug 25 18:38:12 2003
-@@ -25,7 +25,7 @@
- /*
- * BlueZ kernel library.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/kernel.h>
-@@ -105,7 +105,7 @@
- return EACCES;
-
- case 0x06:
-- return EINVAL;
-+ return EBADE;
-
- case 0x07:
- return ENOMEM;
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/Config.in linux-2.4.18-mh9/net/bluetooth/rfcomm/Config.in
---- linux-2.4.18/net/bluetooth/rfcomm/Config.in Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/rfcomm/Config.in Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,10 @@
-+#
-+# Bluetooth RFCOMM layer configuration
-+#
-+
-+dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
-+
-+if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
-+ bool ' RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
-+fi
-+
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/Makefile linux-2.4.18-mh9/net/bluetooth/rfcomm/Makefile
---- linux-2.4.18/net/bluetooth/rfcomm/Makefile Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/rfcomm/Makefile Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,11 @@
-+#
-+# Makefile for the Linux Bluetooth RFCOMM layer
-+#
-+
-+O_TARGET := rfcomm.o
-+
-+obj-y := core.o sock.o crc.o
-+obj-$(CONFIG_BLUEZ_RFCOMM_TTY) += tty.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/core.c linux-2.4.18-mh9/net/bluetooth/rfcomm/core.c
---- linux-2.4.18/net/bluetooth/rfcomm/core.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/rfcomm/core.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,1951 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ RPN support - Dirk Husemann <hud@zurich.ibm.com>
-+*/
-+
-+/*
-+ * RFCOMM core.
-+ *
-+ * $Id$
-+ */
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/init.h>
-+#include <linux/wait.h>
-+#include <linux/net.h>
-+#include <linux/proc_fs.h>
-+#include <net/sock.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#define VERSION "1.0"
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+struct task_struct *rfcomm_thread;
-+DECLARE_MUTEX(rfcomm_sem);
-+unsigned long rfcomm_event;
-+
-+static LIST_HEAD(session_list);
-+static atomic_t terminate, running;
-+
-+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
-+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
-+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
-+static int rfcomm_queue_disc(struct rfcomm_dlc *d);
-+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
-+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
-+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
-+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
-+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
-+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
-+
-+static void rfcomm_process_connect(struct rfcomm_session *s);
-+
-+/* ---- RFCOMM frame parsing macros ---- */
-+#define __get_dlci(b) ((b & 0xfc) >> 2)
-+#define __get_channel(b) ((b & 0xf8) >> 3)
-+#define __get_dir(b) ((b & 0x04) >> 2)
-+#define __get_type(b) ((b & 0xef))
-+
-+#define __test_ea(b) ((b & 0x01))
-+#define __test_cr(b) ((b & 0x02))
-+#define __test_pf(b) ((b & 0x10))
-+
-+#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
-+#define __ctrl(type, pf) (((type & 0xef) | (pf << 4)))
-+#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir)
-+#define __srv_channel(dlci) (dlci >> 1)
-+#define __dir(dlci) (dlci & 0x01)
-+
-+#define __len8(len) (((len) << 1) | 1)
-+#define __len16(len) ((len) << 1)
-+
-+/* MCC macros */
-+#define __mcc_type(cr, type) (((type << 2) | (cr << 1) | 0x01))
-+#define __get_mcc_type(b) ((b & 0xfc) >> 2)
-+#define __get_mcc_len(b) ((b & 0xfe) >> 1)
-+
-+/* RPN macros */
-+#define __rpn_line_settings(data, stop, parity) ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
-+#define __get_rpn_data_bits(line) ((line) & 0x3)
-+#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
-+#define __get_rpn_parity(line) (((line) >> 3) & 0x3)
-+
-+/* ---- RFCOMM FCS computation ---- */
-+
-+/* CRC on 2 bytes */
-+#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
-+
-+/* FCS on 2 bytes */
-+static inline u8 __fcs(u8 *data)
-+{
-+ return (0xff - __crc(data));
-+}
-+
-+/* FCS on 3 bytes */
-+static inline u8 __fcs2(u8 *data)
-+{
-+ return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
-+}
-+
-+/* Check FCS */
-+static inline int __check_fcs(u8 *data, int type, u8 fcs)
-+{
-+ u8 f = __crc(data);
-+
-+ if (type != RFCOMM_UIH)
-+ f = rfcomm_crc_table[f ^ data[2]];
-+
-+ return rfcomm_crc_table[f ^ fcs] != 0xcf;
-+}
-+
-+/* ---- L2CAP callbacks ---- */
-+static void rfcomm_l2state_change(struct sock *sk)
-+{
-+ BT_DBG("%p state %d", sk, sk->state);
-+ rfcomm_schedule(RFCOMM_SCHED_STATE);
-+}
-+
-+static void rfcomm_l2data_ready(struct sock *sk, int bytes)
-+{
-+ BT_DBG("%p bytes %d", sk, bytes);
-+ rfcomm_schedule(RFCOMM_SCHED_RX);
-+}
-+
-+static int rfcomm_l2sock_create(struct socket **sock)
-+{
-+ int err;
-+
-+ BT_DBG("");
-+
-+ err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
-+ if (!err) {
-+ struct sock *sk = (*sock)->sk;
-+ sk->data_ready = rfcomm_l2data_ready;
-+ sk->state_change = rfcomm_l2state_change;
-+ }
-+ return err;
-+}
-+
-+/* ---- RFCOMM DLCs ---- */
-+static void rfcomm_dlc_timeout(unsigned long arg)
-+{
-+ struct rfcomm_dlc *d = (void *) arg;
-+
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ set_bit(RFCOMM_TIMED_OUT, &d->flags);
-+ rfcomm_dlc_put(d);
-+ rfcomm_schedule(RFCOMM_SCHED_TIMEO);
-+}
-+
-+static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
-+{
-+ BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
-+
-+ if (!mod_timer(&d->timer, jiffies + timeout))
-+ rfcomm_dlc_hold(d);
-+}
-+
-+static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ if (timer_pending(&d->timer) && del_timer(&d->timer))
-+ rfcomm_dlc_put(d);
-+}
-+
-+static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("%p", d);
-+
-+ d->state = BT_OPEN;
-+ d->flags = 0;
-+ d->mscex = 0;
-+ d->mtu = RFCOMM_DEFAULT_MTU;
-+ d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
-+
-+ d->credits = 0;
-+ d->rx_credits = RFCOMM_DEFAULT_CREDITS;
-+}
-+
-+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
-+{
-+ struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
-+ if (!d)
-+ return NULL;
-+ memset(d, 0, sizeof(*d));
-+
-+ init_timer(&d->timer);
-+ d->timer.function = rfcomm_dlc_timeout;
-+ d->timer.data = (unsigned long) d;
-+
-+ skb_queue_head_init(&d->tx_queue);
-+ spin_lock_init(&d->lock);
-+ atomic_set(&d->refcnt, 1);
-+
-+ rfcomm_dlc_clear_state(d);
-+
-+ BT_DBG("%p", d);
-+ return d;
-+}
-+
-+void rfcomm_dlc_free(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("%p", d);
-+
-+ skb_queue_purge(&d->tx_queue);
-+ kfree(d);
-+}
-+
-+static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p session %p", d, s);
-+
-+ rfcomm_session_hold(s);
-+
-+ rfcomm_dlc_hold(d);
-+ list_add(&d->list, &s->dlcs);
-+ d->session = s;
-+}
-+
-+static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
-+{
-+ struct rfcomm_session *s = d->session;
-+
-+ BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
-+
-+ list_del(&d->list);
-+ d->session = NULL;
-+ rfcomm_dlc_put(d);
-+
-+ rfcomm_session_put(s);
-+}
-+
-+static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p;
-+
-+ list_for_each(p, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ if (d->dlci == dlci)
-+ return d;
-+ }
-+ return NULL;
-+}
-+
-+static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-+{
-+ struct rfcomm_session *s;
-+ int err = 0;
-+ u8 dlci;
-+
-+ BT_DBG("dlc %p state %ld %s %s channel %d",
-+ d, d->state, batostr(src), batostr(dst), channel);
-+
-+ if (channel < 1 || channel > 30)
-+ return -EINVAL;
-+
-+ if (d->state != BT_OPEN && d->state != BT_CLOSED)
-+ return 0;
-+
-+ s = rfcomm_session_get(src, dst);
-+ if (!s) {
-+ s = rfcomm_session_create(src, dst, &err);
-+ if (!s)
-+ return err;
-+ }
-+
-+ dlci = __dlci(!s->initiator, channel);
-+
-+ /* Check if DLCI already exists */
-+ if (rfcomm_dlc_get(s, dlci))
-+ return -EBUSY;
-+
-+ rfcomm_dlc_clear_state(d);
-+
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ d->priority = 7;
-+
-+ d->state = BT_CONFIG;
-+ rfcomm_dlc_link(s, d);
-+
-+ d->mtu = s->mtu;
-+ d->credits = s->credits;
-+
-+ if (s->state == BT_CONNECTED)
-+ rfcomm_send_pn(s, 1, d);
-+ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-+ return 0;
-+}
-+
-+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-+{
-+ mm_segment_t fs;
-+ int r;
-+
-+ rfcomm_lock();
-+
-+ fs = get_fs(); set_fs(KERNEL_DS);
-+ r = __rfcomm_dlc_open(d, src, dst, channel);
-+ set_fs(fs);
-+
-+ rfcomm_unlock();
-+ return r;
-+}
-+
-+static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-+{
-+ struct rfcomm_session *s = d->session;
-+ if (!s)
-+ return 0;
-+
-+ BT_DBG("dlc %p state %ld dlci %d err %d session %p",
-+ d, d->state, d->dlci, err, s);
-+
-+ switch (d->state) {
-+ case BT_CONNECTED:
-+ case BT_CONFIG:
-+ case BT_CONNECT:
-+ d->state = BT_DISCONN;
-+ if (skb_queue_empty(&d->tx_queue)) {
-+ rfcomm_send_disc(s, d->dlci);
-+ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
-+ } else {
-+ rfcomm_queue_disc(d);
-+ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
-+ }
-+ break;
-+
-+ default:
-+ rfcomm_dlc_clear_timer(d);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CLOSED;
-+ d->state_change(d, err);
-+ rfcomm_dlc_unlock(d);
-+
-+ skb_queue_purge(&d->tx_queue);
-+ rfcomm_dlc_unlink(d);
-+ }
-+
-+ return 0;
-+}
-+
-+int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-+{
-+ mm_segment_t fs;
-+ int r;
-+
-+ rfcomm_lock();
-+
-+ fs = get_fs(); set_fs(KERNEL_DS);
-+ r = __rfcomm_dlc_close(d, err);
-+ set_fs(fs);
-+
-+ rfcomm_unlock();
-+ return r;
-+}
-+
-+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
-+{
-+ int len = skb->len;
-+
-+ if (d->state != BT_CONNECTED)
-+ return -ENOTCONN;
-+
-+ BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
-+
-+ if (len > d->mtu)
-+ return -EINVAL;
-+
-+ rfcomm_make_uih(skb, d->addr);
-+ skb_queue_tail(&d->tx_queue, skb);
-+
-+ if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+ return len;
-+}
-+
-+void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ if (!d->credits) {
-+ d->v24_sig |= RFCOMM_V24_FC;
-+ set_bit(RFCOMM_MSC_PENDING, &d->flags);
-+ }
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+}
-+
-+void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-+{
-+ BT_DBG("dlc %p state %ld", d, d->state);
-+
-+ if (!d->credits) {
-+ d->v24_sig &= ~RFCOMM_V24_FC;
-+ set_bit(RFCOMM_MSC_PENDING, &d->flags);
-+ }
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+}
-+
-+/*
-+ Set/get modem status functions use _local_ status i.e. what we report
-+ to the other side.
-+ Remote status is provided by dlc->modem_status() callback.
-+ */
-+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
-+{
-+ BT_DBG("dlc %p state %ld v24_sig 0x%x",
-+ d, d->state, v24_sig);
-+
-+ if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+ v24_sig |= RFCOMM_V24_FC;
-+ else
-+ v24_sig &= ~RFCOMM_V24_FC;
-+
-+ d->v24_sig = v24_sig;
-+
-+ if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+
-+ return 0;
-+}
-+
-+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
-+{
-+ BT_DBG("dlc %p state %ld v24_sig 0x%x",
-+ d, d->state, d->v24_sig);
-+
-+ *v24_sig = d->v24_sig;
-+ return 0;
-+}
-+
-+/* ---- RFCOMM sessions ---- */
-+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
-+{
-+ struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
-+ if (!s)
-+ return NULL;
-+ memset(s, 0, sizeof(*s));
-+
-+ BT_DBG("session %p sock %p", s, sock);
-+
-+ INIT_LIST_HEAD(&s->dlcs);
-+ s->state = state;
-+ s->sock = sock;
-+
-+ s->mtu = RFCOMM_DEFAULT_MTU;
-+ s->credits = 0;
-+
-+ list_add(&s->list, &session_list);
-+
-+ /* Do not increment module usage count for listeting sessions.
-+ * Otherwise we won't be able to unload the module. */
-+ if (state != BT_LISTEN)
-+ MOD_INC_USE_COUNT;
-+ return s;
-+}
-+
-+void rfcomm_session_del(struct rfcomm_session *s)
-+{
-+ int state = s->state;
-+
-+ BT_DBG("session %p state %ld", s, s->state);
-+
-+ list_del(&s->list);
-+
-+ if (state == BT_CONNECTED)
-+ rfcomm_send_disc(s, 0);
-+
-+ sock_release(s->sock);
-+ kfree(s);
-+
-+ if (state != BT_LISTEN)
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
-+{
-+ struct rfcomm_session *s;
-+ struct list_head *p, *n;
-+ struct bluez_pinfo *pi;
-+ list_for_each_safe(p, n, &session_list) {
-+ s = list_entry(p, struct rfcomm_session, list);
-+ pi = bluez_pi(s->sock->sk);
-+
-+ if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
-+ !bacmp(&pi->dst, dst))
-+ return s;
-+ }
-+ return NULL;
-+}
-+
-+void rfcomm_session_close(struct rfcomm_session *s, int err)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("session %p state %ld err %d", s, s->state, err);
-+
-+ rfcomm_session_hold(s);
-+
-+ s->state = BT_CLOSED;
-+
-+ /* Close all dlcs */
-+ list_for_each_safe(p, n, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, err);
-+ }
-+
-+ rfcomm_session_put(s);
-+}
-+
-+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
-+{
-+ struct rfcomm_session *s = NULL;
-+ struct sockaddr_l2 addr;
-+ struct l2cap_options opts;
-+ struct socket *sock;
-+ int size;
-+
-+ BT_DBG("%s %s", batostr(src), batostr(dst));
-+
-+ *err = rfcomm_l2sock_create(&sock);
-+ if (*err < 0)
-+ return NULL;
-+
-+ bacpy(&addr.l2_bdaddr, src);
-+ addr.l2_family = AF_BLUETOOTH;
-+ addr.l2_psm = 0;
-+ *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-+ if (*err < 0)
-+ goto failed;
-+
-+ /* Set L2CAP options */
-+ size = sizeof(opts);
-+ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
-+
-+ opts.imtu = RFCOMM_MAX_L2CAP_MTU;
-+ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
-+
-+ s = rfcomm_session_add(sock, BT_BOUND);
-+ if (!s) {
-+ *err = -ENOMEM;
-+ goto failed;
-+ }
-+
-+ s->initiator = 1;
-+
-+ bacpy(&addr.l2_bdaddr, dst);
-+ addr.l2_family = AF_BLUETOOTH;
-+ addr.l2_psm = htobs(RFCOMM_PSM);
-+ *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
-+ if (*err == 0 || *err == -EAGAIN)
-+ return s;
-+
-+ rfcomm_session_del(s);
-+ return NULL;
-+
-+failed:
-+ sock_release(sock);
-+ return NULL;
-+}
-+
-+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
-+{
-+ struct sock *sk = s->sock->sk;
-+ if (src)
-+ bacpy(src, &bluez_pi(sk)->src);
-+ if (dst)
-+ bacpy(dst, &bluez_pi(sk)->dst);
-+}
-+
-+/* ---- RFCOMM frame sending ---- */
-+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
-+{
-+ struct socket *sock = s->sock;
-+ struct iovec iv = { data, len };
-+ struct msghdr msg;
-+ int err;
-+
-+ BT_DBG("session %p len %d", s, len);
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 1;
-+ msg.msg_iov = &iv;
-+
-+ err = sock->ops->sendmsg(sock, &msg, len, 0);
-+ return err;
-+}
-+
-+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(!s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_UA, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_queue_disc(struct rfcomm_dlc *d)
-+{
-+ struct rfcomm_cmd *cmd;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("dlc %p dlci %d", d, d->dlci);
-+
-+ skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
-+ if (!skb)
-+ return -ENOMEM;
-+
-+ cmd = (void *) __skb_put(skb, sizeof(*cmd));
-+ cmd->addr = d->addr;
-+ cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
-+ cmd->len = __len8(0);
-+ cmd->fcs = __fcs2((u8 *) cmd);
-+
-+ skb_queue_tail(&d->tx_queue, skb);
-+ rfcomm_schedule(RFCOMM_SCHED_TX);
-+ return 0;
-+}
-+
-+static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_cmd cmd;
-+
-+ BT_DBG("%p dlci %d", s, dlci);
-+
-+ cmd.addr = __addr(!s->initiator, dlci);
-+ cmd.ctrl = __ctrl(RFCOMM_DM, 1);
-+ cmd.len = __len8(0);
-+ cmd.fcs = __fcs2((u8 *) &cmd);
-+
-+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d type %d", s, cr, type);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + 1);
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_NSC);
-+ mcc->len = __len8(1);
-+
-+ /* Type that we didn't like */
-+ *ptr = __mcc_type(cr, type); ptr++;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_pn *pn;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*pn));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_PN);
-+ mcc->len = __len8(sizeof(*pn));
-+
-+ pn = (void *) ptr; ptr += sizeof(*pn);
-+ pn->dlci = d->dlci;
-+ pn->priority = d->priority;
-+ pn->ack_timer = 0;
-+ pn->max_retrans = 0;
-+
-+ if (cr || d->credits) {
-+ pn->flow_ctrl = cr ? 0xf0 : 0xe0;
-+ pn->credits = RFCOMM_DEFAULT_CREDITS;
-+ } else {
-+ pn->flow_ctrl = 0;
-+ pn->credits = 0;
-+ }
-+
-+ pn->mtu = htobs(d->mtu);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
-+ u8 bit_rate, u8 data_bits, u8 stop_bits,
-+ u8 parity, u8 flow_ctrl_settings,
-+ u8 xon_char, u8 xoff_char, u16 param_mask)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_rpn *rpn;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
-+ "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x",
-+ s, cr, dlci, bit_rate, data_bits, stop_bits, parity,
-+ flow_ctrl_settings, xon_char, xoff_char, param_mask);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*rpn));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_RPN);
-+ mcc->len = __len8(sizeof(*rpn));
-+
-+ rpn = (void *) ptr; ptr += sizeof(*rpn);
-+ rpn->dlci = __addr(1, dlci);
-+ rpn->bit_rate = bit_rate;
-+ rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
-+ rpn->flow_ctrl = flow_ctrl_settings;
-+ rpn->xon_char = xon_char;
-+ rpn->xoff_char = xoff_char;
-+ rpn->param_mask = param_mask;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_rls *rls;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d status 0x%x", s, cr, status);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*rls));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_RLS);
-+ mcc->len = __len8(sizeof(*rls));
-+
-+ rls = (void *) ptr; ptr += sizeof(*rls);
-+ rls->dlci = __addr(1, dlci);
-+ rls->status = status;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ struct rfcomm_msc *msc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc) + sizeof(*msc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_MSC);
-+ mcc->len = __len8(sizeof(*msc));
-+
-+ msc = (void *) ptr; ptr += sizeof(*msc);
-+ msc->dlci = __addr(1, dlci);
-+ msc->v24_sig = v24_sig | 0x01;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
-+ mcc->len = __len8(0);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ struct rfcomm_mcc *mcc;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = __addr(s->initiator, 0);
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+ hdr->len = __len8(sizeof(*mcc));
-+
-+ mcc = (void *) ptr; ptr += sizeof(*mcc);
-+ mcc->type = __mcc_type(cr, RFCOMM_FCON);
-+ mcc->len = __len8(0);
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
-+{
-+ struct socket *sock = s->sock;
-+ struct iovec iv[3];
-+ struct msghdr msg;
-+ unsigned char hdr[5], crc[1];
-+
-+ if (len > 125)
-+ return -EINVAL;
-+
-+ BT_DBG("%p cr %d", s, cr);
-+
-+ hdr[0] = __addr(s->initiator, 0);
-+ hdr[1] = __ctrl(RFCOMM_UIH, 0);
-+ hdr[2] = 0x01 | ((len + 2) << 1);
-+ hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
-+ hdr[4] = 0x01 | (len << 1);
-+
-+ crc[0] = __fcs(hdr);
-+
-+ iv[0].iov_base = hdr;
-+ iv[0].iov_len = 5;
-+ iv[1].iov_base = pattern;
-+ iv[1].iov_len = len;
-+ iv[2].iov_base = crc;
-+ iv[2].iov_len = 1;
-+
-+ memset(&msg, 0, sizeof(msg));
-+ msg.msg_iovlen = 3;
-+ msg.msg_iov = iv;
-+ return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
-+}
-+
-+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
-+{
-+ struct rfcomm_hdr *hdr;
-+ u8 buf[16], *ptr = buf;
-+
-+ BT_DBG("%p addr %d credits %d", s, addr, credits);
-+
-+ hdr = (void *) ptr; ptr += sizeof(*hdr);
-+ hdr->addr = addr;
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
-+ hdr->len = __len8(0);
-+
-+ *ptr = credits; ptr++;
-+
-+ *ptr = __fcs(buf); ptr++;
-+
-+ return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
-+{
-+ struct rfcomm_hdr *hdr;
-+ int len = skb->len;
-+ u8 *crc;
-+
-+ if (len > 127) {
-+ hdr = (void *) skb_push(skb, 4);
-+ put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
-+ } else {
-+ hdr = (void *) skb_push(skb, 3);
-+ hdr->len = __len8(len);
-+ }
-+ hdr->addr = addr;
-+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+
-+ crc = skb_put(skb, 1);
-+ *crc = __fcs((void *) hdr);
-+}
-+
-+/* ---- RFCOMM frame reception ---- */
-+static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
-+{
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (dlci) {
-+ /* Data channel */
-+ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+ if (!d) {
-+ rfcomm_send_dm(s, dlci);
-+ return 0;
-+ }
-+
-+ switch (d->state) {
-+ case BT_CONNECT:
-+ rfcomm_dlc_clear_timer(d);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CONNECTED;
-+ d->state_change(d, 0);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+ break;
-+
-+ case BT_DISCONN:
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, 0);
-+ break;
-+ }
-+ } else {
-+ /* Control channel */
-+ switch (s->state) {
-+ case BT_CONNECT:
-+ s->state = BT_CONNECTED;
-+ rfcomm_process_connect(s);
-+ break;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
-+{
-+ int err = 0;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (dlci) {
-+ /* Data DLC */
-+ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ if (d->state == BT_CONNECT || d->state == BT_CONFIG)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, err);
-+ }
-+ } else {
-+ if (s->state == BT_CONNECT)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ s->state = BT_CLOSED;
-+ rfcomm_session_close(s, err);
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
-+{
-+ int err = 0;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (dlci) {
-+ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ rfcomm_send_ua(s, dlci);
-+
-+ if (d->state == BT_CONNECT || d->state == BT_CONFIG)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ d->state = BT_CLOSED;
-+ __rfcomm_dlc_close(d, err);
-+ } else
-+ rfcomm_send_dm(s, dlci);
-+
-+ } else {
-+ rfcomm_send_ua(s, 0);
-+
-+ if (s->state == BT_CONNECT)
-+ err = ECONNREFUSED;
-+ else
-+ err = ECONNRESET;
-+
-+ s->state = BT_CLOSED;
-+ rfcomm_session_close(s, err);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
-+{
-+ struct rfcomm_dlc *d;
-+ u8 channel;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (!dlci) {
-+ rfcomm_send_ua(s, 0);
-+
-+ if (s->state == BT_OPEN) {
-+ s->state = BT_CONNECTED;
-+ rfcomm_process_connect(s);
-+ }
-+ return 0;
-+ }
-+
-+ /* Check if DLC exists */
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ if (d->state == BT_OPEN) {
-+ /* DLC was previously opened by PN request */
-+ rfcomm_send_ua(s, dlci);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CONNECTED;
-+ d->state_change(d, 0);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+ }
-+ return 0;
-+ }
-+
-+ /* Notify socket layer about incomming connection */
-+ channel = __srv_channel(dlci);
-+ if (rfcomm_connect_ind(s, channel, &d)) {
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ rfcomm_dlc_link(s, d);
-+
-+ rfcomm_send_ua(s, dlci);
-+
-+ rfcomm_dlc_lock(d);
-+ d->state = BT_CONNECTED;
-+ d->state_change(d, 0);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+ } else {
-+ rfcomm_send_dm(s, dlci);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
-+{
-+ struct rfcomm_session *s = d->session;
-+
-+ BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
-+ d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
-+
-+ if (cr) {
-+ if (pn->flow_ctrl == 0xf0) {
-+ s->credits = RFCOMM_MAX_CREDITS;
-+ d->credits = s->credits;
-+ d->tx_credits = pn->credits;
-+ } else {
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ d->credits = 0;
-+ }
-+ } else {
-+ if (pn->flow_ctrl == 0xe0) {
-+ s->credits = RFCOMM_MAX_CREDITS;
-+ d->credits = s->credits;
-+ d->tx_credits = pn->credits;
-+ } else {
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ d->credits = 0;
-+ }
-+ }
-+
-+ d->priority = pn->priority;
-+
-+ d->mtu = btohs(pn->mtu);
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+ struct rfcomm_pn *pn = (void *) skb->data;
-+ struct rfcomm_dlc *d;
-+ u8 dlci = pn->dlci;
-+
-+ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+ if (!dlci)
-+ return 0;
-+
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (d) {
-+ if (cr) {
-+ /* PN request */
-+ rfcomm_apply_pn(d, cr, pn);
-+ rfcomm_send_pn(s, 0, d);
-+ } else {
-+ /* PN response */
-+ switch (d->state) {
-+ case BT_CONFIG:
-+ rfcomm_apply_pn(d, cr, pn);
-+
-+ d->state = BT_CONNECT;
-+ rfcomm_send_sabm(s, d->dlci);
-+ break;
-+ }
-+ }
-+ } else {
-+ u8 channel = __srv_channel(dlci);
-+
-+ if (!cr)
-+ return 0;
-+
-+ /* PN request for non existing DLC.
-+ * Assume incomming connection. */
-+ if (rfcomm_connect_ind(s, channel, &d)) {
-+ d->dlci = dlci;
-+ d->addr = __addr(s->initiator, dlci);
-+ rfcomm_dlc_link(s, d);
-+
-+ rfcomm_apply_pn(d, cr, pn);
-+
-+ d->state = BT_OPEN;
-+ rfcomm_send_pn(s, 0, d);
-+ } else {
-+ rfcomm_send_dm(s, dlci);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
-+{
-+ struct rfcomm_rpn *rpn = (void *) skb->data;
-+ u8 dlci = __get_dlci(rpn->dlci);
-+
-+ u8 bit_rate = 0;
-+ u8 data_bits = 0;
-+ u8 stop_bits = 0;
-+ u8 parity = 0;
-+ u8 flow_ctrl = 0;
-+ u8 xon_char = 0;
-+ u8 xoff_char = 0;
-+ u16 rpn_mask = RFCOMM_RPN_PM_ALL;
-+
-+ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
-+ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
-+ rpn->xon_char, rpn->xoff_char, rpn->param_mask);
-+
-+ if (!cr)
-+ return 0;
-+
-+ if (len == 1) {
-+ /* request: return default setting */
-+ bit_rate = RFCOMM_RPN_BR_115200;
-+ data_bits = RFCOMM_RPN_DATA_8;
-+ stop_bits = RFCOMM_RPN_STOP_1;
-+ parity = RFCOMM_RPN_PARITY_NONE;
-+ flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+ xon_char = RFCOMM_RPN_XON_CHAR;
-+ xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+
-+ goto rpn_out;
-+ }
-+ /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
-+ no flow control lines, normal XON/XOFF chars */
-+ if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
-+ bit_rate = rpn->bit_rate;
-+ if (bit_rate != RFCOMM_RPN_BR_115200) {
-+ BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
-+ bit_rate = RFCOMM_RPN_BR_115200;
-+ rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
-+ data_bits = __get_rpn_data_bits(rpn->line_settings);
-+ if (data_bits != RFCOMM_RPN_DATA_8) {
-+ BT_DBG("RPN data bits mismatch 0x%x", data_bits);
-+ data_bits = RFCOMM_RPN_DATA_8;
-+ rpn_mask ^= RFCOMM_RPN_PM_DATA;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
-+ stop_bits = __get_rpn_stop_bits(rpn->line_settings);
-+ if (stop_bits != RFCOMM_RPN_STOP_1) {
-+ BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
-+ stop_bits = RFCOMM_RPN_STOP_1;
-+ rpn_mask ^= RFCOMM_RPN_PM_STOP;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
-+ parity = __get_rpn_parity(rpn->line_settings);
-+ if (parity != RFCOMM_RPN_PARITY_NONE) {
-+ BT_DBG("RPN parity mismatch 0x%x", parity);
-+ parity = RFCOMM_RPN_PARITY_NONE;
-+ rpn_mask ^= RFCOMM_RPN_PM_PARITY;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
-+ flow_ctrl = rpn->flow_ctrl;
-+ if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
-+ BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
-+ flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+ rpn_mask ^= RFCOMM_RPN_PM_FLOW;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
-+ xon_char = rpn->xon_char;
-+ if (xon_char != RFCOMM_RPN_XON_CHAR) {
-+ BT_DBG("RPN XON char mismatch 0x%x", xon_char);
-+ xon_char = RFCOMM_RPN_XON_CHAR;
-+ rpn_mask ^= RFCOMM_RPN_PM_XON;
-+ }
-+ }
-+ if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
-+ xoff_char = rpn->xoff_char;
-+ if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
-+ BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
-+ xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+ rpn_mask ^= RFCOMM_RPN_PM_XOFF;
-+ }
-+ }
-+
-+rpn_out:
-+ rfcomm_send_rpn(s, 0, dlci,
-+ bit_rate, data_bits, stop_bits, parity, flow_ctrl,
-+ xon_char, xoff_char, rpn_mask);
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+ struct rfcomm_rls *rls = (void *) skb->data;
-+ u8 dlci = __get_dlci(rls->dlci);
-+
-+ BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
-+
-+ if (!cr)
-+ return 0;
-+
-+ /* FIXME: We should probably do something with this
-+ information here. But for now it's sufficient just
-+ to reply -- Bluetooth 1.1 says it's mandatory to
-+ recognise and respond to RLS */
-+
-+ rfcomm_send_rls(s, 0, dlci, rls->status);
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+ struct rfcomm_msc *msc = (void *) skb->data;
-+ struct rfcomm_dlc *d;
-+ u8 dlci = __get_dlci(msc->dlci);
-+
-+ BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
-+
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (!d)
-+ return 0;
-+
-+ if (cr) {
-+ if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ else
-+ clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+
-+ rfcomm_dlc_lock(d);
-+ if (d->modem_status)
-+ d->modem_status(d, msc->v24_sig);
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
-+
-+ d->mscex |= RFCOMM_MSCEX_RX;
-+ } else
-+ d->mscex |= RFCOMM_MSCEX_TX;
-+
-+ return 0;
-+}
-+
-+static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
-+{
-+ struct rfcomm_mcc *mcc = (void *) skb->data;
-+ u8 type, cr, len;
-+
-+ cr = __test_cr(mcc->type);
-+ type = __get_mcc_type(mcc->type);
-+ len = __get_mcc_len(mcc->len);
-+
-+ BT_DBG("%p type 0x%x cr %d", s, type, cr);
-+
-+ skb_pull(skb, 2);
-+
-+ switch (type) {
-+ case RFCOMM_PN:
-+ rfcomm_recv_pn(s, cr, skb);
-+ break;
-+
-+ case RFCOMM_RPN:
-+ rfcomm_recv_rpn(s, cr, len, skb);
-+ break;
-+
-+ case RFCOMM_RLS:
-+ rfcomm_recv_rls(s, cr, skb);
-+ break;
-+
-+ case RFCOMM_MSC:
-+ rfcomm_recv_msc(s, cr, skb);
-+ break;
-+
-+ case RFCOMM_FCOFF:
-+ if (cr) {
-+ set_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+ rfcomm_send_fcoff(s, 0);
-+ }
-+ break;
-+
-+ case RFCOMM_FCON:
-+ if (cr) {
-+ clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+ rfcomm_send_fcon(s, 0);
-+ }
-+ break;
-+
-+ case RFCOMM_TEST:
-+ if (cr)
-+ rfcomm_send_test(s, 0, skb->data, skb->len);
-+ break;
-+
-+ case RFCOMM_NSC:
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown control type 0x%02x", type);
-+ rfcomm_send_nsc(s, cr, type);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
-+{
-+ struct rfcomm_dlc *d;
-+
-+ BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
-+
-+ d = rfcomm_dlc_get(s, dlci);
-+ if (!d) {
-+ rfcomm_send_dm(s, dlci);
-+ goto drop;
-+ }
-+
-+ if (pf && d->credits) {
-+ u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
-+
-+ d->tx_credits += credits;
-+ if (d->tx_credits)
-+ clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ }
-+
-+ if (skb->len && d->state == BT_CONNECTED) {
-+ rfcomm_dlc_lock(d);
-+ d->rx_credits--;
-+ d->data_ready(d, skb);
-+ rfcomm_dlc_unlock(d);
-+ return 0;
-+ }
-+
-+drop:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
-+{
-+ struct rfcomm_hdr *hdr = (void *) skb->data;
-+ u8 type, dlci, fcs;
-+
-+ dlci = __get_dlci(hdr->addr);
-+ type = __get_type(hdr->ctrl);
-+
-+ /* Trim FCS */
-+ skb->len--; skb->tail--;
-+ fcs = *(u8 *) skb->tail;
-+
-+ if (__check_fcs(skb->data, type, fcs)) {
-+ BT_ERR("bad checksum in packet");
-+ kfree_skb(skb);
-+ return -EILSEQ;
-+ }
-+
-+ if (__test_ea(hdr->len))
-+ skb_pull(skb, 3);
-+ else
-+ skb_pull(skb, 4);
-+
-+ switch (type) {
-+ case RFCOMM_SABM:
-+ if (__test_pf(hdr->ctrl))
-+ rfcomm_recv_sabm(s, dlci);
-+ break;
-+
-+ case RFCOMM_DISC:
-+ if (__test_pf(hdr->ctrl))
-+ rfcomm_recv_disc(s, dlci);
-+ break;
-+
-+ case RFCOMM_UA:
-+ if (__test_pf(hdr->ctrl))
-+ rfcomm_recv_ua(s, dlci);
-+ break;
-+
-+ case RFCOMM_DM:
-+ rfcomm_recv_dm(s, dlci);
-+ break;
-+
-+ case RFCOMM_UIH:
-+ if (dlci)
-+ return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-+
-+ rfcomm_recv_mcc(s, skb);
-+ break;
-+
-+ default:
-+ BT_ERR("Unknown packet type 0x%02x\n", type);
-+ break;
-+ }
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+/* ---- Connection and data processing ---- */
-+
-+static void rfcomm_process_connect(struct rfcomm_session *s)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("session %p state %ld", s, s->state);
-+
-+ list_for_each_safe(p, n, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ if (d->state == BT_CONFIG) {
-+ d->mtu = s->mtu;
-+ rfcomm_send_pn(s, 1, d);
-+ }
-+ }
-+}
-+
-+/* Send data queued for the DLC.
-+ * Return number of frames left in the queue.
-+ */
-+static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
-+{
-+ struct sk_buff *skb;
-+ int err;
-+
-+ BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d",
-+ d, d->state, d->credits, d->rx_credits, d->tx_credits);
-+
-+ /* Send pending MSC */
-+ if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
-+ rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
-+
-+ if (d->credits) {
-+ /* CFC enabled.
-+ * Give them some credits */
-+ if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
-+ d->rx_credits <= (d->credits >> 2)) {
-+ rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits);
-+ d->rx_credits = d->credits;
-+ }
-+ } else {
-+ /* CFC disabled.
-+ * Give ourselves some credits */
-+ d->tx_credits = 5;
-+ }
-+
-+ if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
-+ return skb_queue_len(&d->tx_queue);
-+
-+ while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-+ err = rfcomm_send_frame(d->session, skb->data, skb->len);
-+ if (err < 0) {
-+ skb_queue_head(&d->tx_queue, skb);
-+ break;
-+ }
-+ kfree_skb(skb);
-+ d->tx_credits--;
-+ }
-+
-+ if (d->credits && !d->tx_credits) {
-+ /* We're out of TX credits.
-+ * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
-+ set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+ }
-+
-+ return skb_queue_len(&d->tx_queue);
-+}
-+
-+static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
-+{
-+ struct rfcomm_dlc *d;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("session %p state %ld", s, s->state);
-+
-+ list_for_each_safe(p, n, &s->dlcs) {
-+ d = list_entry(p, struct rfcomm_dlc, list);
-+ if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
-+ __rfcomm_dlc_close(d, ETIMEDOUT);
-+ continue;
-+ }
-+
-+ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
-+ continue;
-+
-+ if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
-+ d->mscex == RFCOMM_MSCEX_OK)
-+ rfcomm_process_tx(d);
-+ }
-+}
-+
-+static inline void rfcomm_process_rx(struct rfcomm_session *s)
-+{
-+ struct socket *sock = s->sock;
-+ struct sock *sk = sock->sk;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
-+
-+ /* Get data directly from socket receive queue without copying it. */
-+ while ((skb = skb_dequeue(&sk->receive_queue))) {
-+ skb_orphan(skb);
-+ rfcomm_recv_frame(s, skb);
-+ }
-+
-+ if (sk->state == BT_CLOSED) {
-+ if (!s->initiator)
-+ rfcomm_session_put(s);
-+
-+ rfcomm_session_close(s, sk->err);
-+ }
-+}
-+
-+static inline void rfcomm_accept_connection(struct rfcomm_session *s)
-+{
-+ struct socket *sock = s->sock, *nsock;
-+ int err;
-+
-+ /* Fast check for a new connection.
-+ * Avoids unnesesary socket allocations. */
-+ if (list_empty(&bluez_pi(sock->sk)->accept_q))
-+ return;
-+
-+ BT_DBG("session %p", s);
-+
-+ nsock = sock_alloc();
-+ if (!nsock)
-+ return;
-+
-+ nsock->type = sock->type;
-+ nsock->ops = sock->ops;
-+
-+ err = sock->ops->accept(sock, nsock, O_NONBLOCK);
-+ if (err < 0) {
-+ sock_release(nsock);
-+ return;
-+ }
-+
-+ /* Set our callbacks */
-+ nsock->sk->data_ready = rfcomm_l2data_ready;
-+ nsock->sk->state_change = rfcomm_l2state_change;
-+
-+ s = rfcomm_session_add(nsock, BT_OPEN);
-+ if (s)
-+ rfcomm_session_hold(s);
-+ else
-+ sock_release(nsock);
-+}
-+
-+static inline void rfcomm_check_connection(struct rfcomm_session *s)
-+{
-+ struct sock *sk = s->sock->sk;
-+
-+ BT_DBG("%p state %ld", s, s->state);
-+
-+ switch(sk->state) {
-+ case BT_CONNECTED:
-+ s->state = BT_CONNECT;
-+
-+ /* We can adjust MTU on outgoing sessions.
-+ * L2CAP MTU minus UIH header and FCS. */
-+ s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
-+
-+ rfcomm_send_sabm(s, 0);
-+ break;
-+
-+ case BT_CLOSED:
-+ s->state = BT_CLOSED;
-+ rfcomm_session_close(s, sk->err);
-+ break;
-+ }
-+}
-+
-+static inline void rfcomm_process_sessions(void)
-+{
-+ struct list_head *p, *n;
-+
-+ rfcomm_lock();
-+
-+ list_for_each_safe(p, n, &session_list) {
-+ struct rfcomm_session *s;
-+ s = list_entry(p, struct rfcomm_session, list);
-+
-+ if (s->state == BT_LISTEN) {
-+ rfcomm_accept_connection(s);
-+ continue;
-+ }
-+
-+ rfcomm_session_hold(s);
-+
-+ switch (s->state) {
-+ case BT_BOUND:
-+ rfcomm_check_connection(s);
-+ break;
-+
-+ default:
-+ rfcomm_process_rx(s);
-+ break;
-+ }
-+
-+ rfcomm_process_dlcs(s);
-+
-+ rfcomm_session_put(s);
-+ }
-+
-+ rfcomm_unlock();
-+}
-+
-+static void rfcomm_worker(void)
-+{
-+ BT_DBG("");
-+
-+ daemonize(); reparent_to_init();
-+ set_fs(KERNEL_DS);
-+
-+ while (!atomic_read(&terminate)) {
-+ BT_DBG("worker loop event 0x%lx", rfcomm_event);
-+
-+ if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
-+ /* No pending events. Let's sleep.
-+ * Incomming connections and data will wake us up. */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule();
-+ }
-+
-+ /* Process stuff */
-+ clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-+ rfcomm_process_sessions();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ return;
-+}
-+
-+static int rfcomm_add_listener(bdaddr_t *ba)
-+{
-+ struct sockaddr_l2 addr;
-+ struct l2cap_options opts;
-+ struct socket *sock;
-+ struct rfcomm_session *s;
-+ int size, err = 0;
-+
-+ /* Create socket */
-+ err = rfcomm_l2sock_create(&sock);
-+ if (err < 0) {
-+ BT_ERR("Create socket failed %d", err);
-+ return err;
-+ }
-+
-+ /* Bind socket */
-+ bacpy(&addr.l2_bdaddr, ba);
-+ addr.l2_family = AF_BLUETOOTH;
-+ addr.l2_psm = htobs(RFCOMM_PSM);
-+ err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-+ if (err < 0) {
-+ BT_ERR("Bind failed %d", err);
-+ goto failed;
-+ }
-+
-+ /* Set L2CAP options */
-+ size = sizeof(opts);
-+ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
-+
-+ opts.imtu = RFCOMM_MAX_L2CAP_MTU;
-+ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
-+
-+ /* Start listening on the socket */
-+ err = sock->ops->listen(sock, 10);
-+ if (err) {
-+ BT_ERR("Listen failed %d", err);
-+ goto failed;
-+ }
-+
-+ /* Add listening session */
-+ s = rfcomm_session_add(sock, BT_LISTEN);
-+ if (!s)
-+ goto failed;
-+
-+ rfcomm_session_hold(s);
-+ return 0;
-+failed:
-+ sock_release(sock);
-+ return err;
-+}
-+
-+static void rfcomm_kill_listener(void)
-+{
-+ struct rfcomm_session *s;
-+ struct list_head *p, *n;
-+
-+ BT_DBG("");
-+
-+ list_for_each_safe(p, n, &session_list) {
-+ s = list_entry(p, struct rfcomm_session, list);
-+ rfcomm_session_del(s);
-+ }
-+}
-+
-+static int rfcomm_run(void *unused)
-+{
-+ rfcomm_thread = current;
-+
-+ atomic_inc(&running);
-+
-+ daemonize(); reparent_to_init();
-+
-+ sigfillset(&current->blocked);
-+ set_fs(KERNEL_DS);
-+
-+ sprintf(current->comm, "krfcommd");
-+
-+ BT_DBG("");
-+
-+ rfcomm_add_listener(BDADDR_ANY);
-+
-+ rfcomm_worker();
-+
-+ rfcomm_kill_listener();
-+
-+ atomic_dec(&running);
-+ return 0;
-+}
-+
-+/* ---- Proc fs support ---- */
-+static int rfcomm_dlc_dump(char *buf)
-+{
-+ struct rfcomm_session *s;
-+ struct sock *sk;
-+ struct list_head *p, *pp;
-+ char *ptr = buf;
-+
-+ rfcomm_lock();
-+
-+ list_for_each(p, &session_list) {
-+ s = list_entry(p, struct rfcomm_session, list);
-+ sk = s->sock->sk;
-+
-+ list_for_each(pp, &s->dlcs) {
-+ struct rfcomm_dlc *d;
-+ d = list_entry(pp, struct rfcomm_dlc, list);
-+
-+ ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
-+ }
-+ }
-+
-+ rfcomm_unlock();
-+
-+ return ptr - buf;
-+}
-+
-+extern int rfcomm_sock_dump(char *buf);
-+
-+static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+ char *ptr = buf;
-+ int len;
-+
-+ BT_DBG("count %d, offset %ld", count, offset);
-+
-+ ptr += rfcomm_dlc_dump(ptr);
-+ ptr += rfcomm_sock_dump(ptr);
-+ len = ptr - buf;
-+
-+ if (len <= count + offset)
-+ *eof = 1;
-+
-+ *start = buf + offset;
-+ len -= offset;
-+
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+
-+/* ---- Initialization ---- */
-+int __init rfcomm_init(void)
-+{
-+ l2cap_load();
-+
-+ kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+
-+ rfcomm_init_sockets();
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+ rfcomm_init_ttys();
-+#endif
-+
-+ create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
-+
-+ BT_INFO("BlueZ RFCOMM ver %s", VERSION);
-+ BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
-+ BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
-+ return 0;
-+}
-+
-+void rfcomm_cleanup(void)
-+{
-+ /* Terminate working thread.
-+ * ie. Set terminate flag and wake it up */
-+ atomic_inc(&terminate);
-+ rfcomm_schedule(RFCOMM_SCHED_STATE);
-+
-+ /* Wait until thread is running */
-+ while (atomic_read(&running))
-+ schedule();
-+
-+ remove_proc_entry("bluetooth/rfcomm", NULL);
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+ rfcomm_cleanup_ttys();
-+#endif
-+
-+ rfcomm_cleanup_sockets();
-+ return;
-+}
-+
-+module_init(rfcomm_init);
-+module_exit(rfcomm_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/crc.c linux-2.4.18-mh9/net/bluetooth/rfcomm/crc.c
---- linux-2.4.18/net/bluetooth/rfcomm/crc.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/rfcomm/crc.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,71 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * RFCOMM FCS calculation.
-+ *
-+ * $Id$
-+ */
-+
-+/* reversed, 8-bit, poly=0x07 */
-+unsigned char rfcomm_crc_table[256] = {
-+ 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
-+ 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
-+ 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
-+ 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
-+
-+ 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
-+ 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
-+ 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
-+ 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
-+
-+ 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
-+ 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
-+ 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
-+ 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
-+
-+ 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
-+ 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
-+ 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
-+ 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
-+
-+ 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
-+ 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
-+ 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
-+ 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
-+
-+ 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
-+ 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
-+ 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
-+ 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
-+
-+ 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
-+ 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
-+ 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
-+ 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
-+
-+ 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
-+ 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
-+ 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
-+ 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
-+};
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/sock.c linux-2.4.18-mh9/net/bluetooth/rfcomm/sock.c
---- linux-2.4.18/net/bluetooth/rfcomm/sock.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/rfcomm/sock.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,847 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * RFCOMM sockets.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static struct proto_ops rfcomm_sock_ops;
-+
-+static struct bluez_sock_list rfcomm_sk_list = {
-+ lock: RW_LOCK_UNLOCKED
-+};
-+
-+static void rfcomm_sock_close(struct sock *sk);
-+static void rfcomm_sock_kill(struct sock *sk);
-+
-+/* ---- DLC callbacks ----
-+ *
-+ * called under rfcomm_dlc_lock()
-+ */
-+static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
-+{
-+ struct sock *sk = d->owner;
-+ if (!sk)
-+ return;
-+
-+ atomic_add(skb->len, &sk->rmem_alloc);
-+ skb_queue_tail(&sk->receive_queue, skb);
-+ sk->data_ready(sk, skb->len);
-+
-+ if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
-+ rfcomm_dlc_throttle(d);
-+}
-+
-+static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
-+{
-+ struct sock *sk = d->owner, *parent;
-+ if (!sk)
-+ return;
-+
-+ BT_DBG("dlc %p state %ld err %d", d, d->state, err);
-+
-+ bh_lock_sock(sk);
-+
-+ if (err)
-+ sk->err = err;
-+ sk->state = d->state;
-+
-+ parent = bluez_pi(sk)->parent;
-+ if (!parent) {
-+ if (d->state == BT_CONNECTED)
-+ rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
-+ sk->state_change(sk);
-+ } else
-+ parent->data_ready(parent, 0);
-+
-+ bh_unlock_sock(sk);
-+}
-+
-+/* ---- Socket functions ---- */
-+static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
-+{
-+ struct sock *sk;
-+
-+ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
-+ if (rfcomm_pi(sk)->channel == channel &&
-+ !bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+ }
-+
-+ return sk;
-+}
-+
-+/* Find socket with channel and source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-+{
-+ struct sock *sk, *sk1 = NULL;
-+
-+ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
-+ if (state && sk->state != state)
-+ continue;
-+
-+ if (rfcomm_pi(sk)->channel == channel) {
-+ /* Exact match. */
-+ if (!bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+
-+ /* Closest match */
-+ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ sk1 = sk;
-+ }
-+ }
-+ return sk ? sk : sk1;
-+}
-+
-+/* Find socket with given address (channel, src).
-+ * Returns locked socket */
-+static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-+{
-+ struct sock *s;
-+ read_lock(&rfcomm_sk_list.lock);
-+ s = __rfcomm_get_sock_by_channel(state, channel, src);
-+ if (s) bh_lock_sock(s);
-+ read_unlock(&rfcomm_sk_list.lock);
-+ return s;
-+}
-+
-+static void rfcomm_sock_destruct(struct sock *sk)
-+{
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+
-+ BT_DBG("sk %p dlc %p", sk, d);
-+
-+ skb_queue_purge(&sk->receive_queue);
-+ skb_queue_purge(&sk->write_queue);
-+
-+ rfcomm_dlc_lock(d);
-+ rfcomm_pi(sk)->dlc = NULL;
-+
-+ /* Detach DLC if it's owned by this socket */
-+ if (d->owner == sk)
-+ d->owner = NULL;
-+ rfcomm_dlc_unlock(d);
-+
-+ rfcomm_dlc_put(d);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void rfcomm_sock_cleanup_listen(struct sock *parent)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ /* Close not yet accepted dlcs */
-+ while ((sk = bluez_accept_dequeue(parent, NULL))) {
-+ rfcomm_sock_close(sk);
-+ rfcomm_sock_kill(sk);
-+ }
-+
-+ parent->state = BT_CLOSED;
-+ parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_kill(struct sock *sk)
-+{
-+ if (!sk->zapped || sk->socket)
-+ return;
-+
-+ BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
-+
-+ /* Kill poor orphan */
-+ bluez_sock_unlink(&rfcomm_sk_list, sk);
-+ sk->dead = 1;
-+ sock_put(sk);
-+}
-+
-+static void __rfcomm_sock_close(struct sock *sk)
-+{
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+
-+ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-+
-+ switch (sk->state) {
-+ case BT_LISTEN:
-+ rfcomm_sock_cleanup_listen(sk);
-+ break;
-+
-+ case BT_CONNECT:
-+ case BT_CONNECT2:
-+ case BT_CONFIG:
-+ case BT_CONNECTED:
-+ rfcomm_dlc_close(d, 0);
-+
-+ default:
-+ sk->zapped = 1;
-+ break;
-+ }
-+}
-+
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_close(struct sock *sk)
-+{
-+ lock_sock(sk);
-+ __rfcomm_sock_close(sk);
-+ release_sock(sk);
-+}
-+
-+static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ if (parent)
-+ sk->type = parent->type;
-+}
-+
-+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+ struct rfcomm_dlc *d;
-+ struct sock *sk;
-+
-+ sk = sk_alloc(PF_BLUETOOTH, prio, 1);
-+ if (!sk)
-+ return NULL;
-+
-+ d = rfcomm_dlc_alloc(prio);
-+ if (!d) {
-+ sk_free(sk);
-+ return NULL;
-+ }
-+ d->data_ready = rfcomm_sk_data_ready;
-+ d->state_change = rfcomm_sk_state_change;
-+
-+ rfcomm_pi(sk)->dlc = d;
-+ d->owner = sk;
-+
-+ bluez_sock_init(sock, sk);
-+
-+ sk->zapped = 0;
-+
-+ sk->destruct = rfcomm_sock_destruct;
-+ sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
-+
-+ sk->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-+ sk->rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-+
-+ sk->protocol = proto;
-+ sk->state = BT_OPEN;
-+
-+ bluez_sock_link(&rfcomm_sk_list, sk);
-+
-+ BT_DBG("sk %p", sk);
-+
-+ MOD_INC_USE_COUNT;
-+ return sk;
-+}
-+
-+static int rfcomm_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ sock->state = SS_UNCONNECTED;
-+
-+ if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &rfcomm_sock_ops;
-+
-+ if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ rfcomm_sock_init(sk, NULL);
-+ return 0;
-+}
-+
-+static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
-+
-+ if (!addr || addr->sa_family != AF_BLUETOOTH)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_OPEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ write_lock_bh(&rfcomm_sk_list.lock);
-+
-+ if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
-+ err = -EADDRINUSE;
-+ } else {
-+ /* Save source address */
-+ bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
-+ rfcomm_pi(sk)->channel = sa->rc_channel;
-+ sk->state = BT_BOUND;
-+ }
-+
-+ write_unlock_bh(&rfcomm_sk_list.lock);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+ struct sock *sk = sock->sk;
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
-+ return -EINVAL;
-+
-+ if (sk->state != BT_OPEN && sk->state != BT_BOUND)
-+ return -EBADFD;
-+
-+ if (sk->type != SOCK_STREAM)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ sk->state = BT_CONNECT;
-+ bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
-+ rfcomm_pi(sk)->channel = sa->rc_channel;
-+
-+ err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
-+ if (!err)
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int rfcomm_sock_listen(struct socket *sock, int backlog)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_BOUND) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ sk->max_ack_backlog = backlog;
-+ sk->ack_backlog = 0;
-+ sk->state = BT_LISTEN;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct sock *sk = sock->sk, *nsk;
-+ long timeo;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+ BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+ /* Wait for an incoming connection. (wake-one). */
-+ add_wait_queue_exclusive(sk->sleep, &wait);
-+ while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ if (err)
-+ goto done;
-+
-+ newsock->state = SS_CONNECTED;
-+
-+ BT_DBG("new socket %p", nsk);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ sa->rc_family = AF_BLUETOOTH;
-+ sa->rc_channel = rfcomm_pi(sk)->channel;
-+ if (peer)
-+ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
-+ else
-+ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
-+
-+ *len = sizeof(struct sockaddr_rc);
-+ return 0;
-+}
-+
-+static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-+ struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+ struct sk_buff *skb;
-+ int err, size;
-+ int sent = 0;
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ if (sk->shutdown & SEND_SHUTDOWN)
-+ return -EPIPE;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ lock_sock(sk);
-+
-+ while (len) {
-+ size = min_t(uint, len, d->mtu);
-+
-+ skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
-+ msg->msg_flags & MSG_DONTWAIT, &err);
-+ if (!skb)
-+ break;
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
-+ if (err) {
-+ kfree_skb(skb);
-+ sent = err;
-+ break;
-+ }
-+
-+ err = rfcomm_dlc_send(d, skb);
-+ if (err < 0) {
-+ kfree_skb(skb);
-+ break;
-+ }
-+
-+ sent += size;
-+ len -= size;
-+ }
-+
-+ release_sock(sk);
-+
-+ return sent ? sent : err;
-+}
-+
-+static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ add_wait_queue(sk->sleep, &wait);
-+ for (;;) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
-+ signal_pending(current) || !timeo)
-+ break;
-+
-+ set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-+ }
-+
-+ __set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+ return timeo;
-+}
-+
-+static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-+ int flags, struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ int target, err = 0, copied = 0;
-+ long timeo;
-+
-+ if (flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ msg->msg_namelen = 0;
-+
-+ BT_DBG("sk %p size %d", sk, size);
-+
-+ lock_sock(sk);
-+
-+ target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
-+ timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-+
-+ do {
-+ struct sk_buff *skb;
-+ int chunk;
-+
-+ skb = skb_dequeue(&sk->receive_queue);
-+ if (!skb) {
-+ if (copied >= target)
-+ break;
-+
-+ if ((err = sock_error(sk)) != 0)
-+ break;
-+ if (sk->shutdown & RCV_SHUTDOWN)
-+ break;
-+
-+ err = -EAGAIN;
-+ if (!timeo)
-+ break;
-+
-+ timeo = rfcomm_sock_data_wait(sk, timeo);
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ goto out;
-+ }
-+ continue;
-+ }
-+
-+ chunk = min_t(unsigned int, skb->len, size);
-+ if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
-+ skb_queue_head(&sk->receive_queue, skb);
-+ if (!copied)
-+ copied = -EFAULT;
-+ break;
-+ }
-+ copied += chunk;
-+ size -= chunk;
-+
-+ if (!(flags & MSG_PEEK)) {
-+ atomic_sub(chunk, &sk->rmem_alloc);
-+
-+ skb_pull(skb, chunk);
-+ if (skb->len) {
-+ skb_queue_head(&sk->receive_queue, skb);
-+ break;
-+ }
-+ kfree_skb(skb);
-+
-+ } else {
-+ /* put message back and return */
-+ skb_queue_head(&sk->receive_queue, skb);
-+ break;
-+ }
-+ } while (size);
-+
-+out:
-+ if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
-+ rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
-+
-+ release_sock(sk);
-+ return copied ? : err;
-+}
-+
-+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ int len, err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (get_user(len, optlen))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ struct sock *sk = sock->sk;
-+ int err;
-+
-+ lock_sock(sk);
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+ err = rfcomm_dev_ioctl(sk, cmd, arg);
-+#else
-+ err = -EOPNOTSUPP;
-+#endif
-+
-+ release_sock(sk);
-+
-+ return err;
-+}
-+
-+static int rfcomm_sock_shutdown(struct socket *sock, int how)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk) return 0;
-+
-+ lock_sock(sk);
-+ if (!sk->shutdown) {
-+ sk->shutdown = SHUTDOWN_MASK;
-+ __rfcomm_sock_close(sk);
-+
-+ if (sk->linger)
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ }
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int rfcomm_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ err = rfcomm_sock_shutdown(sock, 2);
-+
-+ sock_orphan(sk);
-+ rfcomm_sock_kill(sk);
-+ return err;
-+}
-+
-+/* ---- RFCOMM core layer callbacks ----
-+ *
-+ * called under rfcomm_lock()
-+ */
-+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
-+{
-+ struct sock *sk, *parent;
-+ bdaddr_t src, dst;
-+ int result = 0;
-+
-+ BT_DBG("session %p channel %d", s, channel);
-+
-+ rfcomm_session_getaddr(s, &src, &dst);
-+
-+ /* Check if we have socket listening on this channel */
-+ parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
-+ if (!parent)
-+ return 0;
-+
-+ /* Check for backlog size */
-+ if (parent->ack_backlog > parent->max_ack_backlog) {
-+ BT_DBG("backlog full %d", parent->ack_backlog);
-+ goto done;
-+ }
-+
-+ sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
-+ if (!sk)
-+ goto done;
-+
-+ rfcomm_sock_init(sk, parent);
-+ bacpy(&bluez_pi(sk)->src, &src);
-+ bacpy(&bluez_pi(sk)->dst, &dst);
-+ rfcomm_pi(sk)->channel = channel;
-+
-+ sk->state = BT_CONFIG;
-+ bluez_accept_enqueue(parent, sk);
-+
-+ /* Accept connection and return socket DLC */
-+ *d = rfcomm_pi(sk)->dlc;
-+ result = 1;
-+
-+done:
-+ bh_unlock_sock(parent);
-+ return result;
-+}
-+
-+/* ---- Proc fs support ---- */
-+int rfcomm_sock_dump(char *buf)
-+{
-+ struct bluez_sock_list *list = &rfcomm_sk_list;
-+ struct rfcomm_pinfo *pi;
-+ struct sock *sk;
-+ char *ptr = buf;
-+
-+ write_lock_bh(&list->lock);
-+
-+ for (sk = list->head; sk; sk = sk->next) {
-+ pi = rfcomm_pi(sk);
-+ ptr += sprintf(ptr, "sk %s %s %d %d\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ sk->state, rfcomm_pi(sk)->channel);
-+ }
-+
-+ write_unlock_bh(&list->lock);
-+
-+ return ptr - buf;
-+}
-+
-+static struct proto_ops rfcomm_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: rfcomm_sock_release,
-+ bind: rfcomm_sock_bind,
-+ connect: rfcomm_sock_connect,
-+ listen: rfcomm_sock_listen,
-+ accept: rfcomm_sock_accept,
-+ getname: rfcomm_sock_getname,
-+ sendmsg: rfcomm_sock_sendmsg,
-+ recvmsg: rfcomm_sock_recvmsg,
-+ shutdown: rfcomm_sock_shutdown,
-+ setsockopt: rfcomm_sock_setsockopt,
-+ getsockopt: rfcomm_sock_getsockopt,
-+ ioctl: rfcomm_sock_ioctl,
-+ poll: bluez_sock_poll,
-+ socketpair: sock_no_socketpair,
-+ mmap: sock_no_mmap
-+};
-+
-+static struct net_proto_family rfcomm_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: rfcomm_sock_create
-+};
-+
-+int rfcomm_init_sockets(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
-+ BT_ERR("Can't register RFCOMM socket layer");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+void rfcomm_cleanup_sockets(void)
-+{
-+ int err;
-+
-+ /* Unregister socket, protocol and notifier */
-+ if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
-+ BT_ERR("Can't unregister RFCOMM socket layer %d", err);
-+}
-diff -urN linux-2.4.18/net/bluetooth/rfcomm/tty.c linux-2.4.18-mh9/net/bluetooth/rfcomm/tty.c
---- linux-2.4.18/net/bluetooth/rfcomm/tty.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/rfcomm/tty.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,945 @@
-+/*
-+ RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * RFCOMM TTY.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+
-+#include <linux/slab.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */
-+#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */
-+#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
-+#define RFCOMM_TTY_MINOR 0
-+
-+struct rfcomm_dev {
-+ struct list_head list;
-+ atomic_t refcnt;
-+
-+ char name[12];
-+ int id;
-+ unsigned long flags;
-+ int opened;
-+ int err;
-+
-+ bdaddr_t src;
-+ bdaddr_t dst;
-+ u8 channel;
-+
-+ uint modem_status;
-+
-+ struct rfcomm_dlc *dlc;
-+ struct tty_struct *tty;
-+ wait_queue_head_t wait;
-+ struct tasklet_struct wakeup_task;
-+
-+ atomic_t wmem_alloc;
-+};
-+
-+static LIST_HEAD(rfcomm_dev_list);
-+static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
-+
-+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
-+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
-+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
-+
-+static void rfcomm_tty_wakeup(unsigned long arg);
-+
-+/* ---- Device functions ---- */
-+static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
-+{
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+
-+ BT_DBG("dev %p dlc %p", dev, dlc);
-+
-+ rfcomm_dlc_lock(dlc);
-+ /* Detach DLC if it's owned by this dev */
-+ if (dlc->owner == dev)
-+ dlc->owner = NULL;
-+ rfcomm_dlc_unlock(dlc);
-+
-+ rfcomm_dlc_put(dlc);
-+ kfree(dev);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-+{
-+ atomic_inc(&dev->refcnt);
-+}
-+
-+static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-+{
-+ if (atomic_dec_and_test(&dev->refcnt))
-+ rfcomm_dev_destruct(dev);
-+}
-+
-+static struct rfcomm_dev *__rfcomm_dev_get(int id)
-+{
-+ struct rfcomm_dev *dev;
-+ struct list_head *p;
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ dev = list_entry(p, struct rfcomm_dev, list);
-+ if (dev->id == id)
-+ return dev;
-+ }
-+
-+ return NULL;
-+}
-+
-+static inline struct rfcomm_dev *rfcomm_dev_get(int id)
-+{
-+ struct rfcomm_dev *dev;
-+
-+ read_lock(&rfcomm_dev_lock);
-+ dev = __rfcomm_dev_get(id);
-+ read_unlock(&rfcomm_dev_lock);
-+
-+ if (dev) rfcomm_dev_hold(dev);
-+ return dev;
-+}
-+
-+static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
-+{
-+ struct rfcomm_dev *dev;
-+ struct list_head *head = &rfcomm_dev_list, *p;
-+ int err = 0;
-+
-+ BT_DBG("id %d channel %d", req->dev_id, req->channel);
-+
-+ dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+ memset(dev, 0, sizeof(struct rfcomm_dev));
-+
-+ write_lock_bh(&rfcomm_dev_lock);
-+
-+ if (req->dev_id < 0) {
-+ dev->id = 0;
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
-+ break;
-+
-+ dev->id++;
-+ head = p;
-+ }
-+ } else {
-+ dev->id = req->dev_id;
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
-+
-+ if (entry->id == dev->id) {
-+ err = -EADDRINUSE;
-+ goto out;
-+ }
-+
-+ if (entry->id > dev->id - 1)
-+ break;
-+
-+ head = p;
-+ }
-+ }
-+
-+ if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
-+ err = -ENFILE;
-+ goto out;
-+ }
-+
-+ sprintf(dev->name, "rfcomm%d", dev->id);
-+
-+ list_add(&dev->list, head);
-+ atomic_set(&dev->refcnt, 1);
-+
-+ bacpy(&dev->src, &req->src);
-+ bacpy(&dev->dst, &req->dst);
-+ dev->channel = req->channel;
-+
-+ dev->flags = req->flags &
-+ ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
-+
-+ init_waitqueue_head(&dev->wait);
-+ tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
-+
-+ rfcomm_dlc_lock(dlc);
-+ dlc->data_ready = rfcomm_dev_data_ready;
-+ dlc->state_change = rfcomm_dev_state_change;
-+ dlc->modem_status = rfcomm_dev_modem_status;
-+
-+ dlc->owner = dev;
-+ dev->dlc = dlc;
-+ rfcomm_dlc_unlock(dlc);
-+
-+ MOD_INC_USE_COUNT;
-+
-+out:
-+ write_unlock_bh(&rfcomm_dev_lock);
-+
-+ if (err) {
-+ kfree(dev);
-+ return err;
-+ } else
-+ return dev->id;
-+}
-+
-+static void rfcomm_dev_del(struct rfcomm_dev *dev)
-+{
-+ BT_DBG("dev %p", dev);
-+
-+ write_lock_bh(&rfcomm_dev_lock);
-+ list_del_init(&dev->list);
-+ write_unlock_bh(&rfcomm_dev_lock);
-+
-+ rfcomm_dev_put(dev);
-+}
-+
-+/* ---- Send buffer ---- */
-+
-+static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
-+{
-+ /* We can't let it be zero, because we don't get a callback
-+ when tx_credits becomes nonzero, hence we'd never wake up */
-+ return dlc->mtu * (dlc->tx_credits?:1);
-+}
-+
-+static void rfcomm_wfree(struct sk_buff *skb)
-+{
-+ struct rfcomm_dev *dev = (void *) skb->sk;
-+ atomic_sub(skb->truesize, &dev->wmem_alloc);
-+ if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-+ tasklet_schedule(&dev->wakeup_task);
-+ rfcomm_dev_put(dev);
-+}
-+
-+static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
-+{
-+ rfcomm_dev_hold(dev);
-+ atomic_add(skb->truesize, &dev->wmem_alloc);
-+ skb->sk = (void *) dev;
-+ skb->destructor = rfcomm_wfree;
-+}
-+
-+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority)
-+{
-+ if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
-+ struct sk_buff *skb = alloc_skb(size, priority);
-+ if (skb) {
-+ rfcomm_set_owner_w(skb, dev);
-+ return skb;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+/* ---- Device IOCTLs ---- */
-+
-+#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
-+
-+static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
-+{
-+ struct rfcomm_dev_req req;
-+ struct rfcomm_dlc *dlc;
-+ int id;
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
-+
-+ if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+
-+ if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
-+ /* Socket must be connected */
-+ if (sk->state != BT_CONNECTED)
-+ return -EBADFD;
-+
-+ dlc = rfcomm_pi(sk)->dlc;
-+ rfcomm_dlc_hold(dlc);
-+ } else {
-+ dlc = rfcomm_dlc_alloc(GFP_KERNEL);
-+ if (!dlc)
-+ return -ENOMEM;
-+ }
-+
-+ id = rfcomm_dev_add(&req, dlc);
-+ if (id < 0) {
-+ rfcomm_dlc_put(dlc);
-+ return id;
-+ }
-+
-+ if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
-+ /* DLC is now used by device.
-+ * Socket must be disconnected */
-+ sk->state = BT_CLOSED;
-+ }
-+
-+ return id;
-+}
-+
-+static int rfcomm_release_dev(unsigned long arg)
-+{
-+ struct rfcomm_dev_req req;
-+ struct rfcomm_dev *dev;
-+
-+ if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+ return -EFAULT;
-+
-+ BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
-+
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+
-+ if (!(dev = rfcomm_dev_get(req.dev_id)))
-+ return -ENODEV;
-+
-+ if (req.flags & (1 << RFCOMM_HANGUP_NOW))
-+ rfcomm_dlc_close(dev->dlc, 0);
-+
-+ rfcomm_dev_del(dev);
-+ rfcomm_dev_put(dev);
-+ return 0;
-+}
-+
-+static int rfcomm_get_dev_list(unsigned long arg)
-+{
-+ struct rfcomm_dev_list_req *dl;
-+ struct rfcomm_dev_info *di;
-+ struct list_head *p;
-+ int n = 0, size;
-+ u16 dev_num;
-+
-+ BT_DBG("");
-+
-+ if (get_user(dev_num, (u16 *) arg))
-+ return -EFAULT;
-+
-+ if (!dev_num)
-+ return -EINVAL;
-+
-+ size = sizeof(*dl) + dev_num * sizeof(*di);
-+
-+ if (verify_area(VERIFY_WRITE, (void *)arg, size))
-+ return -EFAULT;
-+
-+ if (!(dl = kmalloc(size, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ di = dl->dev_info;
-+
-+ read_lock_bh(&rfcomm_dev_lock);
-+
-+ list_for_each(p, &rfcomm_dev_list) {
-+ struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
-+ (di + n)->id = dev->id;
-+ (di + n)->flags = dev->flags;
-+ (di + n)->state = dev->dlc->state;
-+ (di + n)->channel = dev->channel;
-+ bacpy(&(di + n)->src, &dev->src);
-+ bacpy(&(di + n)->dst, &dev->dst);
-+ if (++n >= dev_num)
-+ break;
-+ }
-+
-+ read_unlock_bh(&rfcomm_dev_lock);
-+
-+ dl->dev_num = n;
-+ size = sizeof(*dl) + n * sizeof(*di);
-+
-+ copy_to_user((void *) arg, dl, size);
-+ kfree(dl);
-+ return 0;
-+}
-+
-+static int rfcomm_get_dev_info(unsigned long arg)
-+{
-+ struct rfcomm_dev *dev;
-+ struct rfcomm_dev_info di;
-+ int err = 0;
-+
-+ BT_DBG("");
-+
-+ if (copy_from_user(&di, (void *)arg, sizeof(di)))
-+ return -EFAULT;
-+
-+ if (!(dev = rfcomm_dev_get(di.id)))
-+ return -ENODEV;
-+
-+ di.flags = dev->flags;
-+ di.channel = dev->channel;
-+ di.state = dev->dlc->state;
-+ bacpy(&di.src, &dev->src);
-+ bacpy(&di.dst, &dev->dst);
-+
-+ if (copy_to_user((void *)arg, &di, sizeof(di)))
-+ err = -EFAULT;
-+
-+ rfcomm_dev_put(dev);
-+ return err;
-+}
-+
-+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
-+{
-+ BT_DBG("cmd %d arg %ld", cmd, arg);
-+
-+ switch (cmd) {
-+ case RFCOMMCREATEDEV:
-+ return rfcomm_create_dev(sk, arg);
-+
-+ case RFCOMMRELEASEDEV:
-+ return rfcomm_release_dev(arg);
-+
-+ case RFCOMMGETDEVLIST:
-+ return rfcomm_get_dev_list(arg);
-+
-+ case RFCOMMGETDEVINFO:
-+ return rfcomm_get_dev_info(arg);
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+/* ---- DLC callbacks ---- */
-+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
-+{
-+ struct rfcomm_dev *dev = dlc->owner;
-+ struct tty_struct *tty;
-+
-+ if (!dev || !(tty = dev->tty)) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+
-+ BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
-+
-+ if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-+ register int i;
-+ for (i = 0; i < skb->len; i++) {
-+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-+ tty_flip_buffer_push(tty);
-+
-+ tty_insert_flip_char(tty, skb->data[i], 0);
-+ }
-+ tty_flip_buffer_push(tty);
-+ } else
-+ tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
-+
-+ kfree_skb(skb);
-+}
-+
-+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
-+{
-+ struct rfcomm_dev *dev = dlc->owner;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
-+
-+ dev->err = err;
-+ wake_up_interruptible(&dev->wait);
-+
-+ if (dlc->state == BT_CLOSED) {
-+ if (!dev->tty) {
-+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-+ rfcomm_dev_hold(dev);
-+ rfcomm_dev_del(dev);
-+
-+ /* We have to drop DLC lock here, otherwise
-+ * rfcomm_dev_put() will dead lock if it's the last refference */
-+ rfcomm_dlc_unlock(dlc);
-+ rfcomm_dev_put(dev);
-+ rfcomm_dlc_lock(dlc);
-+ }
-+ } else
-+ tty_hangup(dev->tty);
-+ }
-+}
-+
-+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
-+{
-+ struct rfcomm_dev *dev = dlc->owner;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
-+
-+ dev->modem_status =
-+ ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
-+ ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
-+ ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) |
-+ ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0);
-+}
-+
-+/* ---- TTY functions ---- */
-+static void rfcomm_tty_wakeup(unsigned long arg)
-+{
-+ struct rfcomm_dev *dev = (void *) arg;
-+ struct tty_struct *tty = dev->tty;
-+ if (!tty)
-+ return;
-+
-+ BT_DBG("dev %p tty %p", dev, tty);
-+
-+ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-+ (tty->ldisc.write_wakeup)(tty);
-+
-+ wake_up_interruptible(&tty->write_wait);
-+#ifdef SERIAL_HAVE_POLL_WAIT
-+ wake_up_interruptible(&tty->poll_wait);
-+#endif
-+}
-+
-+static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct rfcomm_dev *dev;
-+ struct rfcomm_dlc *dlc;
-+ int err, id;
-+
-+ id = MINOR(tty->device) - tty->driver.minor_start;
-+
-+ BT_DBG("tty %p id %d", tty, id);
-+
-+ dev = rfcomm_dev_get(id);
-+ if (!dev)
-+ return -ENODEV;
-+
-+ BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
-+
-+ if (dev->opened++ != 0)
-+ return 0;
-+
-+ dlc = dev->dlc;
-+
-+ /* Attach TTY and open DLC */
-+
-+ rfcomm_dlc_lock(dlc);
-+ tty->driver_data = dev;
-+ dev->tty = tty;
-+ rfcomm_dlc_unlock(dlc);
-+ set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-+
-+ err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
-+ if (err < 0)
-+ return err;
-+
-+ /* Wait for DLC to connect */
-+ add_wait_queue(&dev->wait, &wait);
-+ while (1) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (dlc->state == BT_CLOSED) {
-+ err = -dev->err;
-+ break;
-+ }
-+
-+ if (dlc->state == BT_CONNECTED)
-+ break;
-+
-+ if (signal_pending(current)) {
-+ err = -EINTR;
-+ break;
-+ }
-+
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&dev->wait, &wait);
-+
-+ return err;
-+}
-+
-+static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
-+
-+ if (--dev->opened == 0) {
-+ /* Close DLC and dettach TTY */
-+ rfcomm_dlc_close(dev->dlc, 0);
-+
-+ clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-+ tasklet_kill(&dev->wakeup_task);
-+
-+ rfcomm_dlc_lock(dev->dlc);
-+ tty->driver_data = NULL;
-+ dev->tty = NULL;
-+ rfcomm_dlc_unlock(dev->dlc);
-+ }
-+
-+ rfcomm_dev_put(dev);
-+}
-+
-+static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ struct sk_buff *skb;
-+ int err = 0, sent = 0, size;
-+
-+ BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
-+
-+ while (count) {
-+ size = min_t(uint, count, dlc->mtu);
-+
-+ if (from_user)
-+ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL);
-+ else
-+ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC);
-+
-+ if (!skb)
-+ break;
-+
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ if (from_user)
-+ copy_from_user(skb_put(skb, size), buf + sent, size);
-+ else
-+ memcpy(skb_put(skb, size), buf + sent, size);
-+
-+ if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
-+ kfree_skb(skb);
-+ break;
-+ }
-+
-+ sent += size;
-+ count -= size;
-+ }
-+
-+ return sent ? sent : err;
-+}
-+
-+static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ struct sk_buff *skb;
-+
-+ BT_DBG("tty %p char %x", tty, ch);
-+
-+ skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC);
-+
-+ if (!skb)
-+ return;
-+
-+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+ *(char *)skb_put(skb, 1) = ch;
-+
-+ if ((rfcomm_dlc_send(dlc, skb)) < 0)
-+ kfree_skb(skb);
-+}
-+
-+static int rfcomm_tty_write_room(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ int room;
-+
-+ BT_DBG("tty %p", tty);
-+
-+ room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
-+ if (room < 0)
-+ room = 0;
-+
-+ return room;
-+}
-+
-+static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
-+{
-+ u8 v24_sig, mask;
-+
-+ BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
-+
-+ if (cmd == TIOCMSET)
-+ v24_sig = 0;
-+ else
-+ rfcomm_dlc_get_modem_status(dlc, &v24_sig);
-+
-+ mask = ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
-+ ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
-+ ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
-+ ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
-+ ((status & TIOCM_RI) ? RFCOMM_V24_IC : 0) |
-+ ((status & TIOCM_CD) ? RFCOMM_V24_DV : 0);
-+
-+ if (cmd == TIOCMBIC)
-+ v24_sig &= ~mask;
-+ else
-+ v24_sig |= mask;
-+
-+ rfcomm_dlc_set_modem_status(dlc, v24_sig);
-+ return 0;
-+}
-+
-+static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+ uint status;
-+ int err;
-+
-+ BT_DBG("tty %p cmd 0x%02x", tty, cmd);
-+
-+ switch (cmd) {
-+ case TCGETS:
-+ BT_DBG("TCGETS is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TCSETS:
-+ BT_DBG("TCSETS is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCMGET:
-+ BT_DBG("TIOCMGET");
-+
-+ return put_user(dev->modem_status, (unsigned int *)arg);
-+
-+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-+ case TIOCMBIS: /* Turns on the lines as specified by the mask */
-+ case TIOCMBIC: /* Turns off the lines as specified by the mask */
-+ if ((err = get_user(status, (unsigned int *)arg)))
-+ return err;
-+ return rfcomm_tty_set_modem_status(cmd, dlc, status);
-+
-+ case TIOCMIWAIT:
-+ BT_DBG("TIOCMIWAIT");
-+ break;
-+
-+ case TIOCGICOUNT:
-+ BT_DBG("TIOCGICOUNT");
-+ break;
-+
-+ case TIOCGSERIAL:
-+ BT_ERR("TIOCGSERIAL is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSSERIAL:
-+ BT_ERR("TIOCSSERIAL is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSERGSTRUCT:
-+ BT_ERR("TIOCSERGSTRUCT is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSERGETLSR:
-+ BT_ERR("TIOCSERGETLSR is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ case TIOCSERCONFIG:
-+ BT_ERR("TIOCSERCONFIG is not supported");
-+ return -ENOIOCTLCMD;
-+
-+ default:
-+ return -ENOIOCTLCMD; /* ioctls which we must ignore */
-+
-+ }
-+
-+ return -ENOIOCTLCMD;
-+}
-+
-+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-+
-+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
-+{
-+ BT_DBG("tty %p", tty);
-+
-+ if ((tty->termios->c_cflag == old->c_cflag) &&
-+ (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
-+ return;
-+
-+ /* handle turning off CRTSCTS */
-+ if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
-+ BT_DBG("turning off CRTSCTS");
-+ }
-+}
-+
-+static void rfcomm_tty_throttle(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ rfcomm_dlc_throttle(dev->dlc);
-+}
-+
-+static void rfcomm_tty_unthrottle(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ rfcomm_dlc_unthrottle(dev->dlc);
-+}
-+
-+static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ struct rfcomm_dlc *dlc = dev->dlc;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ if (skb_queue_len(&dlc->tx_queue))
-+ return dlc->mtu;
-+
-+ return 0;
-+}
-+
-+static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ skb_queue_purge(&dev->dlc->tx_queue);
-+
-+ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-+ tty->ldisc.write_wakeup(tty);
-+}
-+
-+static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
-+{
-+ BT_DBG("tty %p ch %c", tty, ch);
-+}
-+
-+static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-+{
-+ BT_DBG("tty %p timeout %d", tty, timeout);
-+}
-+
-+static void rfcomm_tty_hangup(struct tty_struct *tty)
-+{
-+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+ if (!dev)
-+ return;
-+
-+ BT_DBG("tty %p dev %p", tty, dev);
-+
-+ rfcomm_tty_flush_buffer(tty);
-+
-+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
-+ rfcomm_dev_del(dev);
-+}
-+
-+static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
-+{
-+ return 0;
-+}
-+
-+/* ---- TTY structure ---- */
-+static int rfcomm_tty_refcount; /* If we manage several devices */
-+
-+static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
-+static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
-+static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
-+
-+static struct tty_driver rfcomm_tty_driver = {
-+ magic: TTY_DRIVER_MAGIC,
-+ driver_name: "rfcomm",
-+#ifdef CONFIG_DEVFS_FS
-+ name: "bluetooth/rfcomm/%d",
-+#else
-+ name: "rfcomm",
-+#endif
-+ major: RFCOMM_TTY_MAJOR,
-+ minor_start: RFCOMM_TTY_MINOR,
-+ num: RFCOMM_TTY_PORTS,
-+ type: TTY_DRIVER_TYPE_SERIAL,
-+ subtype: SERIAL_TYPE_NORMAL,
-+ flags: TTY_DRIVER_REAL_RAW,
-+
-+ refcount: &rfcomm_tty_refcount,
-+ table: rfcomm_tty_table,
-+ termios: rfcomm_tty_termios,
-+ termios_locked: rfcomm_tty_termios_locked,
-+
-+ open: rfcomm_tty_open,
-+ close: rfcomm_tty_close,
-+ put_char: rfcomm_tty_put_char,
-+ write: rfcomm_tty_write,
-+ write_room: rfcomm_tty_write_room,
-+ chars_in_buffer: rfcomm_tty_chars_in_buffer,
-+ flush_buffer: rfcomm_tty_flush_buffer,
-+ ioctl: rfcomm_tty_ioctl,
-+ throttle: rfcomm_tty_throttle,
-+ unthrottle: rfcomm_tty_unthrottle,
-+ set_termios: rfcomm_tty_set_termios,
-+ send_xchar: rfcomm_tty_send_xchar,
-+ stop: NULL,
-+ start: NULL,
-+ hangup: rfcomm_tty_hangup,
-+ wait_until_sent: rfcomm_tty_wait_until_sent,
-+ read_proc: rfcomm_tty_read_proc,
-+};
-+
-+int rfcomm_init_ttys(void)
-+{
-+ int i;
-+
-+ /* Initalize our global data */
-+ for (i = 0; i < RFCOMM_TTY_PORTS; i++)
-+ rfcomm_tty_table[i] = NULL;
-+
-+ /* Register the TTY driver */
-+ rfcomm_tty_driver.init_termios = tty_std_termios;
-+ rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-+ rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
-+
-+ if (tty_register_driver(&rfcomm_tty_driver)) {
-+ BT_ERR("Can't register RFCOMM TTY driver");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+void rfcomm_cleanup_ttys(void)
-+{
-+ tty_unregister_driver(&rfcomm_tty_driver);
-+ return;
-+}
-diff -urN linux-2.4.18/net/bluetooth/sco.c linux-2.4.18-mh9/net/bluetooth/sco.c
---- linux-2.4.18/net/bluetooth/sco.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.18-mh9/net/bluetooth/sco.c Mon Aug 25 18:38:12 2003
-@@ -0,0 +1,1019 @@
-+/*
-+ BlueZ - Bluetooth protocol stack for Linux
-+ Copyright (C) 2000-2001 Qualcomm Incorporated
-+
-+ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License version 2 as
-+ published by the Free Software Foundation;
-+
-+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
-+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+
-+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
-+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
-+ SOFTWARE IS DISCLAIMED.
-+*/
-+
-+/*
-+ * BlueZ SCO sockets.
-+ *
-+ * $Id$
-+ */
-+#define VERSION "0.3"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/sco.h>
-+
-+#ifndef SCO_DEBUG
-+#undef BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static struct proto_ops sco_sock_ops;
-+
-+static struct bluez_sock_list sco_sk_list = {
-+ lock: RW_LOCK_UNLOCKED
-+};
-+
-+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
-+static void sco_chan_del(struct sock *sk, int err);
-+static inline struct sock * sco_chan_get(struct sco_conn *conn);
-+
-+static int sco_conn_del(struct hci_conn *conn, int err);
-+
-+static void sco_sock_close(struct sock *sk);
-+static void sco_sock_kill(struct sock *sk);
-+
-+/* ----- SCO timers ------ */
-+static void sco_sock_timeout(unsigned long arg)
-+{
-+ struct sock *sk = (struct sock *) arg;
-+
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ bh_lock_sock(sk);
-+ sk->err = ETIMEDOUT;
-+ sk->state_change(sk);
-+ bh_unlock_sock(sk);
-+
-+ sco_sock_kill(sk);
-+ sock_put(sk);
-+}
-+
-+static void sco_sock_set_timer(struct sock *sk, long timeout)
-+{
-+ BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
-+
-+ if (!mod_timer(&sk->timer, jiffies + timeout))
-+ sock_hold(sk);
-+}
-+
-+static void sco_sock_clear_timer(struct sock *sk)
-+{
-+ BT_DBG("sock %p state %d", sk, sk->state);
-+
-+ if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-+ __sock_put(sk);
-+}
-+
-+static void sco_sock_init_timer(struct sock *sk)
-+{
-+ init_timer(&sk->timer);
-+ sk->timer.function = sco_sock_timeout;
-+ sk->timer.data = (unsigned long)sk;
-+}
-+
-+/* -------- SCO connections --------- */
-+static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
-+{
-+ struct hci_dev *hdev = hcon->hdev;
-+ struct sco_conn *conn;
-+
-+ if ((conn = hcon->sco_data))
-+ return conn;
-+
-+ if (status)
-+ return conn;
-+
-+ if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC)))
-+ return NULL;
-+ memset(conn, 0, sizeof(struct sco_conn));
-+
-+ spin_lock_init(&conn->lock);
-+
-+ hcon->sco_data = conn;
-+ conn->hcon = hcon;
-+
-+ conn->src = &hdev->bdaddr;
-+ conn->dst = &hcon->dst;
-+
-+ if (hdev->sco_mtu > 0)
-+ conn->mtu = hdev->sco_mtu;
-+ else
-+ conn->mtu = 60;
-+
-+ BT_DBG("hcon %p conn %p", hcon, conn);
-+
-+ MOD_INC_USE_COUNT;
-+ return conn;
-+}
-+
-+static int sco_conn_del(struct hci_conn *hcon, int err)
-+{
-+ struct sco_conn *conn;
-+ struct sock *sk;
-+
-+ if (!(conn = hcon->sco_data))
-+ return 0;
-+
-+ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-+
-+ /* Kill socket */
-+ if ((sk = sco_chan_get(conn))) {
-+ bh_lock_sock(sk);
-+ sco_sock_clear_timer(sk);
-+ sco_chan_del(sk, err);
-+ bh_unlock_sock(sk);
-+ sco_sock_kill(sk);
-+ }
-+
-+ hcon->sco_data = NULL;
-+ kfree(conn);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+int sco_connect(struct sock *sk)
-+{
-+ bdaddr_t *src = &bluez_pi(sk)->src;
-+ bdaddr_t *dst = &bluez_pi(sk)->dst;
-+ struct sco_conn *conn;
-+ struct hci_conn *hcon;
-+ struct hci_dev *hdev;
-+ int err = 0;
-+
-+ BT_DBG("%s -> %s", batostr(src), batostr(dst));
-+
-+ if (!(hdev = hci_get_route(dst, src)))
-+ return -EHOSTUNREACH;
-+
-+ hci_dev_lock_bh(hdev);
-+
-+ err = -ENOMEM;
-+
-+ hcon = hci_connect(hdev, SCO_LINK, dst);
-+ if (!hcon)
-+ goto done;
-+
-+ conn = sco_conn_add(hcon, 0);
-+ if (!conn) {
-+ hci_conn_put(hcon);
-+ goto done;
-+ }
-+
-+ /* Update source addr of the socket */
-+ bacpy(src, conn->src);
-+
-+ err = sco_chan_add(conn, sk, NULL);
-+ if (err)
-+ goto done;
-+
-+ if (hcon->state == BT_CONNECTED) {
-+ sco_sock_clear_timer(sk);
-+ sk->state = BT_CONNECTED;
-+ } else {
-+ sk->state = BT_CONNECT;
-+ sco_sock_set_timer(sk, sk->sndtimeo);
-+ }
-+done:
-+ hci_dev_unlock_bh(hdev);
-+ hci_dev_put(hdev);
-+ return err;
-+}
-+
-+static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
-+{
-+ struct sco_conn *conn = sco_pi(sk)->conn;
-+ struct sk_buff *skb;
-+ int err, count;
-+
-+ /* Check outgoing MTU */
-+ if (len > conn->mtu)
-+ return -EINVAL;
-+
-+ BT_DBG("sk %p len %d", sk, len);
-+
-+ count = MIN(conn->mtu, len);
-+ if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
-+ return err;
-+
-+ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-+ err = -EFAULT;
-+ goto fail;
-+ }
-+
-+ if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-+ goto fail;
-+
-+ return count;
-+
-+fail:
-+ kfree_skb(skb);
-+ return err;
-+}
-+
-+static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
-+{
-+ struct sock *sk = sco_chan_get(conn);
-+
-+ if (!sk)
-+ goto drop;
-+
-+ BT_DBG("sk %p len %d", sk, skb->len);
-+
-+ if (sk->state != BT_CONNECTED)
-+ goto drop;
-+
-+ if (!sock_queue_rcv_skb(sk, skb))
-+ return;
-+
-+drop:
-+ kfree_skb(skb);
-+ return;
-+}
-+
-+/* -------- Socket interface ---------- */
-+static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
-+{
-+ struct sock *sk;
-+
-+ for (sk = sco_sk_list.head; sk; sk = sk->next) {
-+ if (!bacmp(&bluez_pi(sk)->src, ba))
-+ break;
-+ }
-+
-+ return sk;
-+}
-+
-+/* Find socket listening on source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *sco_get_sock_listen(bdaddr_t *src)
-+{
-+ struct sock *sk, *sk1 = NULL;
-+
-+ read_lock(&sco_sk_list.lock);
-+
-+ for (sk = sco_sk_list.head; sk; sk = sk->next) {
-+ if (sk->state != BT_LISTEN)
-+ continue;
-+
-+ /* Exact match. */
-+ if (!bacmp(&bluez_pi(sk)->src, src))
-+ break;
-+
-+ /* Closest match */
-+ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+ sk1 = sk;
-+ }
-+
-+ read_unlock(&sco_sk_list.lock);
-+
-+ return sk ? sk : sk1;
-+}
-+
-+static void sco_sock_destruct(struct sock *sk)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ skb_queue_purge(&sk->receive_queue);
-+ skb_queue_purge(&sk->write_queue);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static void sco_sock_cleanup_listen(struct sock *parent)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("parent %p", parent);
-+
-+ /* Close not yet accepted channels */
-+ while ((sk = bluez_accept_dequeue(parent, NULL))) {
-+ sco_sock_close(sk);
-+ sco_sock_kill(sk);
-+ }
-+
-+ parent->state = BT_CLOSED;
-+ parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void sco_sock_kill(struct sock *sk)
-+{
-+ if (!sk->zapped || sk->socket)
-+ return;
-+
-+ BT_DBG("sk %p state %d", sk, sk->state);
-+
-+ /* Kill poor orphan */
-+ bluez_sock_unlink(&sco_sk_list, sk);
-+ sk->dead = 1;
-+ sock_put(sk);
-+}
-+
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void sco_sock_close(struct sock *sk)
-+{
-+ struct sco_conn *conn;
-+
-+ sco_sock_clear_timer(sk);
-+
-+ lock_sock(sk);
-+
-+ conn = sco_pi(sk)->conn;
-+
-+ BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
-+
-+ switch (sk->state) {
-+ case BT_LISTEN:
-+ sco_sock_cleanup_listen(sk);
-+ break;
-+
-+ case BT_CONNECTED:
-+ case BT_CONFIG:
-+ case BT_CONNECT:
-+ case BT_DISCONN:
-+ sco_chan_del(sk, ECONNRESET);
-+ break;
-+
-+ default:
-+ sk->zapped = 1;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+}
-+
-+static void sco_sock_init(struct sock *sk, struct sock *parent)
-+{
-+ BT_DBG("sk %p", sk);
-+
-+ if (parent)
-+ sk->type = parent->type;
-+}
-+
-+static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+ struct sock *sk;
-+
-+ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-+ return NULL;
-+
-+ bluez_sock_init(sock, sk);
-+
-+ sk->zapped = 0;
-+
-+ sk->destruct = sco_sock_destruct;
-+ sk->sndtimeo = SCO_CONN_TIMEOUT;
-+
-+ sk->protocol = proto;
-+ sk->state = BT_OPEN;
-+
-+ sco_sock_init_timer(sk);
-+
-+ bluez_sock_link(&sco_sk_list, sk);
-+
-+ MOD_INC_USE_COUNT;
-+ return sk;
-+}
-+
-+static int sco_sock_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ BT_DBG("sock %p", sock);
-+
-+ sock->state = SS_UNCONNECTED;
-+
-+ if (sock->type != SOCK_SEQPACKET)
-+ return -ESOCKTNOSUPPORT;
-+
-+ sock->ops = &sco_sock_ops;
-+
-+ if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ sco_sock_init(sk, NULL);
-+ return 0;
-+}
-+
-+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+ struct sock *sk = sock->sk;
-+ bdaddr_t *src = &sa->sco_bdaddr;
-+ int err = 0;
-+
-+ BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
-+
-+ if (!addr || addr->sa_family != AF_BLUETOOTH)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_OPEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ write_lock_bh(&sco_sk_list.lock);
-+
-+ if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
-+ err = -EADDRINUSE;
-+ } else {
-+ /* Save source address */
-+ bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
-+ sk->state = BT_BOUND;
-+ }
-+
-+ write_unlock_bh(&sco_sk_list.lock);
-+
-+done:
-+ release_sock(sk);
-+
-+ return err;
-+}
-+
-+static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
-+ return -EINVAL;
-+
-+ if (sk->state != BT_OPEN && sk->state != BT_BOUND)
-+ return -EBADFD;
-+
-+ if (sk->type != SOCK_SEQPACKET)
-+ return -EINVAL;
-+
-+ lock_sock(sk);
-+
-+ /* Set destination address and psm */
-+ bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);
-+
-+ if ((err = sco_connect(sk)))
-+ goto done;
-+
-+ err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+ sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_listen(struct socket *sock, int backlog)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ sk->max_ack_backlog = backlog;
-+ sk->ack_backlog = 0;
-+ sk->state = BT_LISTEN;
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct sock *sk = sock->sk, *ch;
-+ long timeo;
-+ int err = 0;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ goto done;
-+ }
-+
-+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+ BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+ /* Wait for an incoming connection. (wake-one). */
-+ add_wait_queue_exclusive(sk->sleep, &wait);
-+ while (!(ch = bluez_accept_dequeue(sk, newsock))) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!timeo) {
-+ err = -EAGAIN;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ timeo = schedule_timeout(timeo);
-+ lock_sock(sk);
-+
-+ if (sk->state != BT_LISTEN) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (signal_pending(current)) {
-+ err = sock_intr_errno(timeo);
-+ break;
-+ }
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(sk->sleep, &wait);
-+
-+ if (err)
-+ goto done;
-+
-+ newsock->state = SS_CONNECTED;
-+
-+ BT_DBG("new socket %p", ch);
-+
-+done:
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+ struct sock *sk = sock->sk;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ addr->sa_family = AF_BLUETOOTH;
-+ *len = sizeof(struct sockaddr_sco);
-+
-+ if (peer)
-+ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
-+ else
-+ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);
-+
-+ return 0;
-+}
-+
-+static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (sk->err)
-+ return sock_error(sk);
-+
-+ if (msg->msg_flags & MSG_OOB)
-+ return -EOPNOTSUPP;
-+
-+ lock_sock(sk);
-+
-+ if (sk->state == BT_CONNECTED)
-+ err = sco_send_frame(sk, msg, len);
-+ else
-+ err = -ENOTCONN;
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+ struct sock *sk = sock->sk;
-+ struct sco_options opts;
-+ struct sco_conninfo cinfo;
-+ int len, err = 0;
-+
-+ BT_DBG("sk %p", sk);
-+
-+ if (get_user(len, optlen))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch (optname) {
-+ case SCO_OPTIONS:
-+ if (sk->state != BT_CONNECTED) {
-+ err = -ENOTCONN;
-+ break;
-+ }
-+
-+ opts.mtu = sco_pi(sk)->conn->mtu;
-+
-+ BT_DBG("mtu %d", opts.mtu);
-+
-+ len = MIN(len, sizeof(opts));
-+ if (copy_to_user(optval, (char *)&opts, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ case SCO_CONNINFO:
-+ if (sk->state != BT_CONNECTED) {
-+ err = -ENOTCONN;
-+ break;
-+ }
-+
-+ cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
-+
-+ len = MIN(len, sizeof(cinfo));
-+ if (copy_to_user(optval, (char *)&cinfo, len))
-+ err = -EFAULT;
-+
-+ break;
-+
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ };
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
-+static int sco_sock_release(struct socket *sock)
-+{
-+ struct sock *sk = sock->sk;
-+ int err = 0;
-+
-+ BT_DBG("sock %p, sk %p", sock, sk);
-+
-+ if (!sk)
-+ return 0;
-+
-+ sco_sock_close(sk);
-+ if (sk->linger) {
-+ lock_sock(sk);
-+ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+ release_sock(sk);
-+ }
-+
-+ sock_orphan(sk);
-+ sco_sock_kill(sk);
-+ return err;
-+}
-+
-+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ BT_DBG("conn %p", conn);
-+
-+ sco_pi(sk)->conn = conn;
-+ conn->sk = sk;
-+
-+ if (parent)
-+ bluez_accept_enqueue(parent, sk);
-+}
-+
-+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+ int err = 0;
-+
-+ sco_conn_lock(conn);
-+ if (conn->sk) {
-+ err = -EBUSY;
-+ } else {
-+ __sco_chan_add(conn, sk, parent);
-+ }
-+ sco_conn_unlock(conn);
-+ return err;
-+}
-+
-+static inline struct sock * sco_chan_get(struct sco_conn *conn)
-+{
-+ struct sock *sk = NULL;
-+ sco_conn_lock(conn);
-+ sk = conn->sk;
-+ sco_conn_unlock(conn);
-+ return sk;
-+}
-+
-+/* Delete channel.
-+ * Must be called on the locked socket. */
-+static void sco_chan_del(struct sock *sk, int err)
-+{
-+ struct sco_conn *conn;
-+
-+ conn = sco_pi(sk)->conn;
-+
-+ BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-+
-+ if (conn) {
-+ sco_conn_lock(conn);
-+ conn->sk = NULL;
-+ sco_pi(sk)->conn = NULL;
-+ sco_conn_unlock(conn);
-+ hci_conn_put(conn->hcon);
-+ }
-+
-+ sk->state = BT_CLOSED;
-+ sk->err = err;
-+ sk->state_change(sk);
-+
-+ sk->zapped = 1;
-+}
-+
-+static void sco_conn_ready(struct sco_conn *conn)
-+{
-+ struct sock *parent, *sk;
-+
-+ BT_DBG("conn %p", conn);
-+
-+ sco_conn_lock(conn);
-+
-+ if ((sk = conn->sk)) {
-+ sco_sock_clear_timer(sk);
-+ bh_lock_sock(sk);
-+ sk->state = BT_CONNECTED;
-+ sk->state_change(sk);
-+ bh_unlock_sock(sk);
-+ } else {
-+ parent = sco_get_sock_listen(conn->src);
-+ if (!parent)
-+ goto done;
-+
-+ bh_lock_sock(parent);
-+
-+ sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
-+ if (!sk) {
-+ bh_unlock_sock(parent);
-+ goto done;
-+ }
-+
-+ sco_sock_init(sk, parent);
-+
-+ bacpy(&bluez_pi(sk)->src, conn->src);
-+ bacpy(&bluez_pi(sk)->dst, conn->dst);
-+
-+ hci_conn_hold(conn->hcon);
-+ __sco_chan_add(conn, sk, parent);
-+
-+ sk->state = BT_CONNECTED;
-+
-+ /* Wake up parent */
-+ parent->data_ready(parent, 1);
-+
-+ bh_unlock_sock(parent);
-+ }
-+
-+done:
-+ sco_conn_unlock(conn);
-+}
-+
-+/* ----- SCO interface with lower layer (HCI) ----- */
-+int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-+
-+ /* Always accept connection */
-+ return HCI_LM_ACCEPT;
-+}
-+
-+int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-+
-+ if (hcon->type != SCO_LINK)
-+ return 0;
-+
-+ if (!status) {
-+ struct sco_conn *conn;
-+
-+ conn = sco_conn_add(hcon, status);
-+ if (conn)
-+ sco_conn_ready(conn);
-+ } else
-+ sco_conn_del(hcon, bterr(status));
-+
-+ return 0;
-+}
-+
-+int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
-+{
-+ BT_DBG("hcon %p reason %d", hcon, reason);
-+
-+ if (hcon->type != SCO_LINK)
-+ return 0;
-+
-+ sco_conn_del(hcon, bterr(reason));
-+ return 0;
-+}
-+
-+int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
-+{
-+ struct sco_conn *conn = hcon->sco_data;
-+
-+ if (!conn)
-+ goto drop;
-+
-+ BT_DBG("conn %p len %d", conn, skb->len);
-+
-+ if (skb->len) {
-+ sco_recv_frame(conn, skb);
-+ return 0;
-+ }
-+
-+drop:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+/* ----- Proc fs support ------ */
-+static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
-+{
-+ struct sco_pinfo *pi;
-+ struct sock *sk;
-+ char *ptr = buf;
-+
-+ write_lock_bh(&list->lock);
-+
-+ for (sk = list->head; sk; sk = sk->next) {
-+ pi = sco_pi(sk);
-+ ptr += sprintf(ptr, "%s %s %d\n",
-+ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+ sk->state);
-+ }
-+
-+ write_unlock_bh(&list->lock);
-+
-+ ptr += sprintf(ptr, "\n");
-+
-+ return ptr - buf;
-+}
-+
-+static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+ char *ptr = buf;
-+ int len;
-+
-+ BT_DBG("count %d, offset %ld", count, offset);
-+
-+ ptr += sco_sock_dump(ptr, &sco_sk_list);
-+ len = ptr - buf;
-+
-+ if (len <= count + offset)
-+ *eof = 1;
-+
-+ *start = buf + offset;
-+ len -= offset;
-+
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+
-+static struct proto_ops sco_sock_ops = {
-+ family: PF_BLUETOOTH,
-+ release: sco_sock_release,
-+ bind: sco_sock_bind,
-+ connect: sco_sock_connect,
-+ listen: sco_sock_listen,
-+ accept: sco_sock_accept,
-+ getname: sco_sock_getname,
-+ sendmsg: sco_sock_sendmsg,
-+ recvmsg: bluez_sock_recvmsg,
-+ poll: bluez_sock_poll,
-+ socketpair: sock_no_socketpair,
-+ ioctl: sock_no_ioctl,
-+ shutdown: sock_no_shutdown,
-+ setsockopt: sco_sock_setsockopt,
-+ getsockopt: sco_sock_getsockopt,
-+ mmap: sock_no_mmap
-+};
-+
-+static struct net_proto_family sco_sock_family_ops = {
-+ family: PF_BLUETOOTH,
-+ create: sco_sock_create
-+};
-+
-+static struct hci_proto sco_hci_proto = {
-+ name: "SCO",
-+ id: HCI_PROTO_SCO,
-+ connect_ind: sco_connect_ind,
-+ connect_cfm: sco_connect_cfm,
-+ disconn_ind: sco_disconn_ind,
-+ recv_scodata: sco_recv_scodata,
-+};
-+
-+int __init sco_init(void)
-+{
-+ int err;
-+
-+ if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
-+ BT_ERR("Can't register SCO socket layer");
-+ return err;
-+ }
-+
-+ if ((err = hci_register_proto(&sco_hci_proto))) {
-+ BT_ERR("Can't register SCO protocol");
-+ return err;
-+ }
-+
-+ create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
-+
-+ BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
-+ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+ return 0;
-+}
-+
-+void sco_cleanup(void)
-+{
-+ int err;
-+
-+ remove_proc_entry("bluetooth/sco", NULL);
-+
-+ /* Unregister socket, protocol and notifier */
-+ if ((err = bluez_sock_unregister(BTPROTO_SCO)))
-+ BT_ERR("Can't unregister SCO socket layer %d", err);
-+
-+ if ((err = hci_unregister_proto(&sco_hci_proto)))
-+ BT_ERR("Can't unregister SCO protocol %d", err);
-+}
-+
-+module_init(sco_init);
-+module_exit(sco_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.18/net/bluetooth/syms.c linux-2.4.18-mh9/net/bluetooth/syms.c
---- linux-2.4.18/net/bluetooth/syms.c Fri Sep 7 18:28:38 2001
-+++ linux-2.4.18-mh9/net/bluetooth/syms.c Mon Aug 25 18:38:12 2003
-@@ -25,7 +25,7 @@
- /*
- * BlueZ symbols.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
-@@ -39,25 +39,28 @@
- #include <linux/socket.h>
-
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
-
- /* HCI Core */
- EXPORT_SYMBOL(hci_register_dev);
- EXPORT_SYMBOL(hci_unregister_dev);
-+EXPORT_SYMBOL(hci_suspend_dev);
-+EXPORT_SYMBOL(hci_resume_dev);
-+
- EXPORT_SYMBOL(hci_register_proto);
- EXPORT_SYMBOL(hci_unregister_proto);
--EXPORT_SYMBOL(hci_register_notifier);
--EXPORT_SYMBOL(hci_unregister_notifier);
-
-+EXPORT_SYMBOL(hci_get_route);
- EXPORT_SYMBOL(hci_connect);
--EXPORT_SYMBOL(hci_disconnect);
- EXPORT_SYMBOL(hci_dev_get);
-+EXPORT_SYMBOL(hci_conn_auth);
-+EXPORT_SYMBOL(hci_conn_encrypt);
-
- EXPORT_SYMBOL(hci_recv_frame);
- EXPORT_SYMBOL(hci_send_acl);
- EXPORT_SYMBOL(hci_send_sco);
--EXPORT_SYMBOL(hci_send_raw);
-+EXPORT_SYMBOL(hci_send_cmd);
-+EXPORT_SYMBOL(hci_si_event);
-
- /* BlueZ lib */
- EXPORT_SYMBOL(bluez_dump);
-@@ -68,5 +71,11 @@
- /* BlueZ sockets */
- EXPORT_SYMBOL(bluez_sock_register);
- EXPORT_SYMBOL(bluez_sock_unregister);
-+EXPORT_SYMBOL(bluez_sock_init);
- EXPORT_SYMBOL(bluez_sock_link);
- EXPORT_SYMBOL(bluez_sock_unlink);
-+EXPORT_SYMBOL(bluez_sock_recvmsg);
-+EXPORT_SYMBOL(bluez_sock_poll);
-+EXPORT_SYMBOL(bluez_accept_enqueue);
-+EXPORT_SYMBOL(bluez_accept_dequeue);
-+EXPORT_SYMBOL(bluez_sock_wait_state);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/cacko.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/cacko.patch
deleted file mode 100644
index e69de29bb2..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/cacko.patch
+++ /dev/null
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/defconfig-collie b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/defconfig-collie
deleted file mode 100644
index 531c7385e3..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/defconfig-collie
+++ /dev/null
@@ -1,1283 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# System Type
-#
-# CONFIG_ARCH_ANAKIN is not set
-# CONFIG_ARCH_ARCA5K is not set
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_MX1ADS is not set
-# CONFIG_ARCH_RPC is not set
-CONFIG_ARCH_SA1100=y
-# CONFIG_ARCH_SHARK is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
-
-#
-# SA11x0 Implementations
-#
-# CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_ADSBITSY is not set
-# CONFIG_SA1100_BRUTUS is not set
-# CONFIG_SA1100_CEP is not set
-# CONFIG_SA1100_CERF is not set
-CONFIG_SA1100_COLLIE=y
-CONFIG_LOCOMO=y
-# CONFIG_COLLIE_TS is not set
-# CONFIG_COLLIE_TR0 is not set
-# CONFIG_COLLIE_TR1 is not set
-# CONFIG_COLLIE_DEV is not set
-# CONFIG_COLLIE_G is not set
-CONFIG_COLLIE_UP=y
-# CONFIG_SA1100_H3100 is not set
-# CONFIG_SA1100_H3600 is not set
-# CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_H3XXX is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FLEXANET is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_FRODO is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_GRAPHICSMASTER is not set
-# CONFIG_SA1100_BADGE4 is not set
-# CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
-# CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
-# CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_PT_SYSTEM3 is not set
-# CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SHERMAN is not set
-# CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_H3600_SLEEVE is not set
-
-#
-# Intel PXA250/210 Implementations
-#
-# CONFIG_ARCH_LUBBOCK is not set
-# CONFIG_ARCH_PXA_IDP is not set
-# CONFIG_ARCH_PXA_CERF is not set
-# CONFIG_COTULLA_DMA is not set
-# CONFIG_SABINAL_DISCOVERY is not set
-# CONFIG_ARCH_SABINAL is not set
-# CONFIG_ARCH_PXA_POODLE is not set
-# CONFIG_POODLE_TR0 is not set
-# CONFIG_ARCH_PXA_CORGI is not set
-# CONFIG_CORGI_TR0 is not set
-CONFIG_ARCH_SHARP_SL=y
-# CONFIG_PXA_USB is not set
-# CONFIG_PXA_USB_NETLINK is not set
-# CONFIG_PXA_USB_CHAR is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_AUTCPU12 is not set
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_FORTUNET is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
-
-#
-# Processor Type
-#
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_PLD is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-CONFIG_CPU_SA1100=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_DISCONTIGMEM=y
-
-#
-# General setup
-#
-# CONFIG_PCI is not set
-CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0
-CONFIG_ZBOOT_ROM_BSS=0
-# CONFIG_CPU_FREQ is not set
-CONFIG_HOTPLUG=y
-
-#
-# PCMCIA/CardBus support
-#
-CONFIG_PCMCIA=y
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
-# CONFIG_TCIC is not set
-# CONFIG_PCMCIA_CLPS6700 is not set
-CONFIG_PCMCIA_SA1100=y
-# CONFIG_PCMCIA_PXA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-
-#
-# At least one math emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_PM=y
-CONFIG_APM=y
-# CONFIG_APM_IGNORE_USER_SUSPEND is not set
-CONFIG_APM_CPU_IDLE=y
-CONFIG_APM_DISPLAY_BLANK=y
-CONFIG_APM_RTC_IS_GMT=y
-# CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="See OE File"
-# CONFIG_SHARPSL_BOOTLDR_PARAMS is not set
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
-CONFIG_FREEPG_SIGNAL=y
-CONFIG_OOM_KILL_SURVIVAL=y
-CONFIG_DEVICEINFO=m
-CONFIG_COLLIE_DEVICEINFO=m
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_CACKO_HYBRID_PARTITIONS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-# CONFIG_MTD_CFI is not set
-# CONFIG_MTD_JEDECPROBE is not set
-# CONFIG_MTD_GEN_PROBE is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_CFI_STAA is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-CONFIG_MTD_COLLIE=y
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_JEDEC is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_LUBBOCK is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
-CONFIG_MTD_SA1100=y
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_FORTUNET is not set
-# CONFIG_MTD_PXA_CERF is not set
-# CONFIG_MTD_EPXA10DB is not set
-# CONFIG_MTD_AUTCPU12 is not set
-# CONFIG_MTD_EDB7312 is not set
-# CONFIG_MTD_IMPA7 is not set
-# CONFIG_MTD_DISCOVERY is not set
-# CONFIG_MTD_SHARP_SL is not set
-# CONFIG_MTD_PCI is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDROM_SA1100 is not set
-CONFIG_MTD_MTDRAM_SA1100=y
-CONFIG_MTDRAM_TOTAL_SIZE=16384
-CONFIG_MTDRAM_ERASE_SIZE=1
-CONFIG_MTDRAM_ABS_POS=C1000000
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_MTDRAM_SHARP_SL is not set
-# CONFIG_MTD_BLKMTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-CONFIG_IPV6=m
-
-#
-# IPv6: Netfilter Configuration
-#
-CONFIG_IP6_NF_QUEUE=m
-CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
-CONFIG_IP6_NF_MATCH_MULTIPORT=m
-CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
-CONFIG_IP6_NF_FILTER=m
-CONFIG_IP6_NF_TARGET_LOG=m
-CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-CONFIG_IPSEC=m
-
-#
-# IPSec options (Openswan)
-#
-CONFIG_IPSEC_IPIP=y
-CONFIG_IPSEC_AH=y
-# CONFIG_IPSEC_AUTH_HMAC_MD5 is not set
-CONFIG_IPSEC_AUTH_HMAC_SHA1=y
-CONFIG_IPSEC_ESP=y
-CONFIG_IPSEC_ENC_3DES=y
-# CONFIG_IPSEC_ENC_AES is not set
-CONFIG_IPSEC_ALG=y
-CONFIG_IPSEC_IPCOMP=y
-CONFIG_IPSEC_DEBUG=y
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_ARM_AM79C961A is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=y
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=y
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-CONFIG_PPP_BSDCOMP=y
-# CONFIG_PPPOE is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-# CONFIG_STRIP is not set
-# CONFIG_WAVELAN is not set
-# CONFIG_ARLAN is not set
-# CONFIG_AIRONET4500 is not set
-# CONFIG_AIRONET4500_NONCS is not set
-# CONFIG_AIRONET4500_PROC is not set
-# CONFIG_AIRO is not set
-# CONFIG_HERMES is not set
-
-#
-# Wireless Pcmcia cards support
-#
-# CONFIG_PCMCIA_HERMES is not set
-# CONFIG_AIRO_CS is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# PCMCIA network device support
-#
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=m
-CONFIG_PCMCIA_3C574=m
-CONFIG_PCMCIA_FMVJ18X=m
-CONFIG_PCMCIA_PCNET=y
-CONFIG_PCMCIA_AXNET=m
-CONFIG_PCMCIA_NMCLAN=m
-CONFIG_PCMCIA_SMC91C92=m
-CONFIG_PCMCIA_XIRC2PS=m
-# CONFIG_ARCNET_COM20020_CS is not set
-# CONFIG_PCMCIA_IBMTR is not set
-CONFIG_NET_PCMCIA_RADIO=y
-# CONFIG_PCMCIA_RAYCS is not set
-# CONFIG_PCMCIA_NETWAVE is not set
-# CONFIG_PCMCIA_WAVELAN is not set
-# CONFIG_AIRONET4500_CS is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-CONFIG_IRDA=y
-
-#
-# IrDA protocols
-#
-# CONFIG_IRLAN is not set
-CONFIG_IRNET=m
-CONFIG_IRCOMM=y
-# CONFIG_IRDA_ULTRA is not set
-
-#
-# IrDA options
-#
-# CONFIG_IRDA_CACHE_LAST_LSAP is not set
-CONFIG_IRDA_FAST_RR=y
-# CONFIG_IRDA_DEBUG is not set
-
-#
-# Infrared-port device drivers
-#
-
-#
-# SIR device drivers
-#
-CONFIG_IRTTY_SIR=y
-CONFIG_IRPORT_SIR=y
-
-#
-# Dongle support
-#
-# CONFIG_DONGLE is not set
-
-#
-# FIR device drivers
-#
-# CONFIG_USB_IRDA is not set
-# CONFIG_NSC_FIR is not set
-# CONFIG_WINBOND_FIR is not set
-# CONFIG_TOSHIBA_FIR is not set
-# CONFIG_SMC_IRCC_FIR is not set
-# CONFIG_ALI_FIR is not set
-# CONFIG_VLSI_FIR is not set
-CONFIG_SA1100_FIR=y
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-CONFIG_BLK_DEV_IDECS=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_UINPUT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-CONFIG_SERIAL_COLLIE=y
-# CONFIG_SERIAL_COLLIE_CONSOLE is not set
-CONFIG_COLLIE_DEFAULT_BAUDRATE=9600
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
-# CONFIG_SERIAL_SA1100 is not set
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
-# CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
-CONFIG_UCB1200=y
-CONFIG_TOUCHSCREEN_UCB1200=y
-# CONFIG_AUDIO_UCB1200 is not set
-# CONFIG_ADC_UCB1200 is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# L3 serial bus support
-#
-# CONFIG_L3 is not set
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
-
-#
-# Other L3 adapters
-#
-# CONFIG_L3_SA1111 is not set
-# CONFIG_BIT_SA1100_GPIO is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_SA1100_RTC=y
-# CONFIG_COTULLA_RTC is not set
-# CONFIG_ADS7846_TS is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-
-#
-# PCMCIA character devices
-#
-CONFIG_PCMCIA_SERIAL_CS=y
-CONFIG_PCMCIA_CHRDEV=y
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FS_SYNC is not set
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_PROC_FS is not set
-# CONFIG_JFFS2_NODEMERGE is not set
-# CONFIG_JFFS2_DYNFRAGTREE is not set
-CONFIG_CRAMFS=y
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-CONFIG_MINIX_FS=y
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_SMB_FS=y
-CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_SMB_NLS_REMOTE="UTF8"
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-# CONFIG_ZISOFS_FS is not set
-CONFIG_ZLIB_FS_INFLATE=y
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="UFT8"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_NLS_UTF8=y
-
-#
-# Console drivers
-#
-CONFIG_PC_KEYMAP=y
-# CONFIG_VGA_CONSOLE is not set
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_COLLIE=y
-# CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
-# CONFIG_FB_CLPS711X is not set
-# CONFIG_FB_SA1100 is not set
-# CONFIG_FB_PXA is not set
-# CONFIG_FB_COTULLA is not set
-# CONFIG_FB_POODLE is not set
-# CONFIG_FB_CORGI is not set
-# CONFIG_SHARP_LOGO_SCREEN is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
-# CONFIG_FBCON_CFB8 is not set
-CONFIG_FBCON_CFB16=y
-# CONFIG_FBCON_CFB24 is not set
-# CONFIG_FBCON_CFB32 is not set
-# CONFIG_FBCON_AFB is not set
-# CONFIG_FBCON_ILBM is not set
-# CONFIG_FBCON_IPLAN2P2 is not set
-# CONFIG_FBCON_IPLAN2P4 is not set
-# CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
-# CONFIG_FBCON_VGA_PLANES is not set
-# CONFIG_FBCON_VGA is not set
-# CONFIG_FBCON_HGA is not set
-CONFIG_FBCON_ROTATE_R=y
-# CONFIG_FBCON_ROTATE_L is not set
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_5x8 is not set
-CONFIG_FONT_4x6=y
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-# CONFIG_SOUND_BT878 is not set
-CONFIG_SOUND_COLLIE_SSP=y
-CONFIG_COLLIE_PCM1741=y
-# CONFIG_COLLIE_PCM1717 is not set
-CONFIG_SOUND_COLLIE_TC35143=y
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_MIDI_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
-# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_MIDI_VIA82CXXX is not set
-# CONFIG_SOUND_SA1100 is not set
-# CONFIG_SOUND_UDA1341 is not set
-# CONFIG_SOUND_ASSABET_UDA1341 is not set
-# CONFIG_SOUND_H3600_UDA1341 is not set
-# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
-# CONFIG_SOUND_SA1111_UDA1341 is not set
-# CONFIG_SOUND_SA1100SSP is not set
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_WAVEARTIST is not set
-# CONFIG_SOUND_PXA_AC97 is not set
-# CONFIG_SOUND_POODLE is not set
-# CONFIG_SOUND_CORGI is not set
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# Multimedia Capabilities Port drivers
-#
-# CONFIG_MCP is not set
-# CONFIG_MCP_SA1100 is not set
-# CONFIG_MCP_UCB1200 is not set
-# CONFIG_MCP_UCB1200_AUDIO is not set
-# CONFIG_MCP_UCB1200_TS is not set
-# CONFIG_MCP_UCB1400_TS is not set
-
-#
-# USB support
-#
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-# CONFIG_USB_OHCI_SA1111 is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-
-#
-# USB Bluetooth can only be used with disabled Bluetooth subsystem
-#
-
-#
-# SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-# Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# USB Device Support
-#
-CONFIG_USBD=m
-CONFIG_USBD_VENDORID=4dd
-CONFIG_USBD_PRODUCTID=8002
-CONFIG_USBD_PRODUCT_NAME="SL Series"
-CONFIG_USBD_MANUFACTURER="Sharp"
-CONFIG_USBD_USE_SERIAL_NUMBER=y
-CONFIG_USBD_SERIAL_NUMBER_STR="A01234"
-CONFIG_USBD_SELFPOWERED=y
-CONFIG_USBD_MONITOR=m
-
-#
-#
-#
-CONFIG_USBD_PROCFS=y
-
-#
-# USB Device functions
-#
-
-#
-# Network Function
-#
-CONFIG_USBD_NET=m
-CONFIG_USBD_NET_VENDORID=4DD
-CONFIG_USBD_NET_PRODUCTID=8004
-CONFIG_USBD_NET_IFNAME="usbd"
-CONFIG_USBD_NET_OUT_ENDPOINT=1
-CONFIG_USBD_NET_OUT_PKTSIZE=64
-CONFIG_USBD_NET_IN_ENDPOINT=2
-CONFIG_USBD_NET_IN_PKTSIZE=64
-# CONFIG_USBD_NET_ALWAYSUP is not set
-# CONFIG_USBD_NET_SAFE is not set
-# CONFIG_USBD_NET_MDLM is not set
-CONFIG_USBD_NET_CDC=y
-CONFIG_USBD_NET_REMOTE_MACADDR="400002000001"
-CONFIG_USBD_NET_REMOTE_OUI=400002
-# CONFIG_USBD_MAC_AS_SERIAL_NUMBER is not set
-CONFIG_USBD_NET_LOCAL_MACADDR="400001000001"
-CONFIG_USBD_NET_LOCAL_OUI=400001
-
-#
-# Serial Function
-#
-CONFIG_USBD_SERIAL=m
-CONFIG_USBD_SERIAL_VENDORID=4dd
-CONFIG_USBD_SERIAL_PRODUCTID=8002
-# CONFIG_USBD_SERIAL_CDC is not set
-CONFIG_USBD_SERIAL_OUT_ENDPOINT=1
-CONFIG_USBD_SERIAL_IN_PKTSIZE=64
-CONFIG_USBD_SERIAL_IN_ENDPOINT=2
-CONFIG_USBD_SERIAL_OUT_PKTSIZE=64
-# CONFIG_USBD_SERIAL_SAFE is not set
-
-#
-# USB Device bus interfaces
-#
-
-#
-# USB Device Bus Interface Support
-#
-CONFIG_USBD_SA1100_BUS=m
-# CONFIG_USBD_TRAFFIC_KEEPAWAKE is not set
-CONFIG_USBD_STALL_TIMEOUT=0
-CONFIG_USBD_STALL_DISCONNECT_DURATION=2
-# CONFIG_USBD_GENERIC_BUS is not set
-
-#
-# Bluetooth support
-#
-CONFIG_BLUEZ=m
-CONFIG_BLUEZ_L2CAP=m
-CONFIG_BLUEZ_SCO=m
-CONFIG_BLUEZ_RFCOMM=m
-CONFIG_BLUEZ_RFCOMM_TTY=y
-CONFIG_BLUEZ_BNEP=m
-CONFIG_BLUEZ_BNEP_MC_FILTER=y
-CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
-# CONFIG_BLUEZ_HIDP is not set
-
-#
-# Bluetooth device drivers
-#
-# CONFIG_BLUEZ_HCIUSB is not set
-CONFIG_BLUEZ_HCIUART=m
-CONFIG_BLUEZ_HCIUART_H4=y
-CONFIG_BLUEZ_HCIUART_BCSP=y
-CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
-# CONFIG_BLUEZ_HCIBFUSB is not set
-CONFIG_BLUEZ_HCIDTL1=m
-CONFIG_BLUEZ_HCIBT3C=m
-CONFIG_BLUEZ_HCIBLUECARD=m
-CONFIG_BLUEZ_HCIBTUART=m
-# CONFIG_BLUEZ_HCIVHCI is not set
-
-#
-# Kernel hacking
-#
-CONFIG_FRAME_POINTER=y
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_COREDUMP_SIGNAL is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_NO_PGT_CACHE is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_ERRORS is not set
-# CONFIG_DEBUG_LL is not set
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch
deleted file mode 100644
index 79ba036323..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-
-#
-# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
-#
-
---- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200
-+++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200
-@@ -15,9 +15,6 @@
- tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
- if [ "$CONFIG_PCMCIA" != "n" ]; then
- # yes, I really mean the following...
-- if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
-- define_bool CONFIG_PCMCIA_PROBE y
-- fi
- if [ "$CONFIG_PCI" != "n" ]; then
- bool ' CardBus support' CONFIG_CARDBUS
- fi
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch
deleted file mode 100644
index 62038c34e2..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch
+++ /dev/null
@@ -1,77 +0,0 @@
---- linux/drivers/ide/ide-cs.c 2003-02-28 17:04:00.000000000 -0600
-+++ linux.new/drivers/ide/ide-cs.c 2003-02-28 17:18:53.000000000 -0600
-@@ -2,7 +2,7 @@
-
- A driver for PCMCIA IDE/ATA disk cards
-
-- ide_cs.c 1.26 1999/11/16 02:10:49
-+ ide-cs.c 1.26 1999/11/16 02:10:49
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
-@@ -66,7 +66,7 @@
- MODULE_PARM(pc_debug, "i");
- #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
- static char *version =
--"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
-+"ide-cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
- #else
- #define DEBUG(n, args...)
- #endif
-@@ -110,7 +110,7 @@
- static int ide_event(event_t event, int priority,
- event_callback_args_t *args);
-
--static dev_info_t dev_info = "ide_cs";
-+static dev_info_t dev_info = "ide-cs";
-
- static dev_link_t *ide_attach(void);
- static void ide_detach(dev_link_t *);
-@@ -356,7 +356,7 @@
- }
-
- if (hd < 0) {
-- printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
-+ printk(KERN_NOTICE "ide-cs: ide_register() at 0x%03x & 0x%03x"
- ", irq %u failed\n", io_base, ctl_base,
- link->irq.AssignedIRQ);
- goto failed;
-@@ -369,7 +369,7 @@
- info->node.minor = 0;
- info->hd = hd;
- link->dev = &info->node;
-- printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-+ printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
- info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
- link->conf.Vpp1/10, link->conf.Vpp1%10);
-
-@@ -409,9 +409,9 @@
- MOD_DEC_USE_COUNT;
- }
-
-- request_region(link->io.BasePort1, link->io.NumPorts1,"ide_cs");
-+ request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
- if (link->io.NumPorts2)
-- request_region(link->io.BasePort2, link->io.NumPorts2,"ide_cs");
-+ request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
-
- info->ndev = 0;
- link->dev = NULL;
-@@ -508,7 +508,7 @@
- DEBUG(0, "%s\n", version);
- CardServices(GetCardServicesInfo, &serv);
- if (serv.Revision != CS_RELEASE_CODE) {
-- printk(KERN_NOTICE "ide_cs: Card Services release "
-+ printk(KERN_NOTICE "ide-cs: Card Services release "
- "does not match!\n");
- return -1;
- }
-@@ -518,7 +518,7 @@
-
- static void __exit exit_ide_cs(void)
- {
-- DEBUG(0, "ide_cs: unloading\n");
-+ DEBUG(0, "ide-cs: unloading\n");
- unregister_pccard_driver(&dev_info);
- while (dev_list != NULL)
- ide_detach(dev_list);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch
deleted file mode 100644
index a672631194..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch
+++ /dev/null
@@ -1,14 +0,0 @@
---- linux/init/main.c 2002-02-25 13:38:13.000000000 -0600
-+++ linux.new/init/main.c 2003-03-16 11:49:45.000000000 -0600
-@@ -830,8 +830,10 @@
- * trying to recover a really broken machine.
- */
-
-- if (execute_command)
-+ if (execute_command) {
-+ argv_init[0] = execute_command;
- execve(execute_command,argv_init,envp_init);
-+ }
- execve("/sbin/init",argv_init,envp_init);
- execve("/etc/init",argv_init,envp_init);
- execve("/bin/init",argv_init,envp_init);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff
deleted file mode 100644
index 2ebfd8ec12..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff
+++ /dev/null
@@ -1,399 +0,0 @@
-diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h
---- linux/include/linux/wireless.14.h Mon Dec 2 18:51:00 2002
-+++ linux/include/linux/wireless.h Mon Dec 2 18:53:35 2002
-@@ -1,7 +1,7 @@
- /*
- * This file define a set of standard wireless extensions
- *
-- * Version : 14 25.1.02
-+ * Version : 15 12.7.02
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
-@@ -80,7 +80,7 @@
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
--#define WIRELESS_EXT 14
-+#define WIRELESS_EXT 15
-
- /*
- * Changes :
-@@ -153,17 +153,32 @@
- * - Define additional specific event numbers
- * - Add "addr" and "param" fields in union iwreq_data
- * - AP scanning stuff (SIOCSIWSCAN and friends)
-+ *
-+ * V14 to V15
-+ * ----------
-+ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
-+ * - Make struct iw_freq signed (both m & e), add explicit padding
-+ * - Add IWEVCUSTOM for driver specific event/scanning token
-+ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses
-+ * - Add IW_TXPOW_RANGE for range of Tx Powers
-+ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
-+ * - Add IW_MODE_MONITOR for passive monitor
- */
-
- /**************************** CONSTANTS ****************************/
-
- /* -------------------------- IOCTL LIST -------------------------- */
-
--/* Basic operations */
-+/* Wireless Identification */
- #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */
- #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
--#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */
--#define SIOCGIWNWID 0x8B03 /* get network id */
-+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
-+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
-+ * Don't put the name of your driver there, it's useless. */
-+
-+/* Basic operations */
-+#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */
-+#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */
- #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */
- #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */
- #define SIOCSIWMODE 0x8B06 /* set operation mode */
-@@ -178,16 +193,18 @@
- #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */
- #define SIOCSIWSTATS 0x8B0E /* Unused */
- #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */
-+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
-+ * is never passed to the driver (i.e. the driver will never see it). */
-
--/* Mobile IP support */
-+/* Mobile IP support (statistics per MAC address) */
- #define SIOCSIWSPY 0x8B10 /* set spy addresses */
- #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */
-
- /* Access Point manipulation */
- #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
- #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */
--#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */
--#define SIOCSIWSCAN 0x8B18 /* trigger scanning */
-+#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */
-+#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */
- #define SIOCGIWSCAN 0x8B19 /* get scanning results */
-
- /* 802.11 specific support */
-@@ -197,9 +214,7 @@
- #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */
- /* As the ESSID and NICKN are strings 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 (promiscuous).
-- */
-+ * point to a string in user space, like it is done for RANGE... */
-
- /* Other parameters useful in 802.11 and some other devices */
- #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */
-@@ -257,7 +272,10 @@
- /* Most events use the same identifier as ioctl requests */
-
- #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */
--#define IWEVQUAL 0x8C01 /* Quality part of statistics */
-+#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */
-+#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */
-+#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */
-+#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */
-
- #define IWEVFIRST 0x8C00
-
-@@ -273,7 +291,8 @@
- #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */
- #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */
- #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */
--#define IW_PRIV_TYPE_FLOAT 0x5000
-+#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */
-+#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */
-
- #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */
-
-@@ -297,13 +316,16 @@
-
- /* Maximum tx powers in the range struct */
- #define IW_MAX_TXPOWER 8
-+/* Note : if you more than 8 TXPowers, just set the max and min or
-+ * a few of them in the struct iw_range. */
-
- /* Maximum of address that you may set with SPY */
--#define IW_MAX_SPY 8
-+#define IW_MAX_SPY 8 /* set */
-+#define IW_MAX_GET_SPY 64 /* get */
-
- /* Maximum of address that you may get in the
- list of access points in range */
--#define IW_MAX_AP 8
-+#define IW_MAX_AP 64
-
- /* Maximum size of the ESSID and NICKN strings */
- #define IW_ESSID_MAX_SIZE 32
-@@ -315,6 +337,7 @@
- #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */
- #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
- #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
-+#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
-
- /* Maximum number of size of encoding token available
- * they are listed in the range structure */
-@@ -350,8 +373,10 @@
- #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
-
- /* Transmit Power flags available */
-+#define IW_TXPOW_TYPE 0x00FF /* Type of value */
- #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
- #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
-+#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
-
- /* Retry limits and lifetime flags available */
- #define IW_RETRY_ON 0x0000 /* No details... */
-@@ -376,6 +401,9 @@
- /* Maximum size of returned data */
- #define IW_SCAN_MAX_DATA 4096 /* In bytes */
-
-+/* Max number of char in custom event - use multiple of them if needed */
-+#define IW_CUSTOM_MAX 256 /* In bytes */
-+
- /****************************** TYPES ******************************/
-
- /* --------------------------- SUBTYPES --------------------------- */
-@@ -411,9 +439,10 @@ struct iw_point
- */
- struct iw_freq
- {
-- __u32 m; /* Mantissa */
-- __u16 e; /* Exponent */
-+ __s32 m; /* Mantissa */
-+ __s16 e; /* Exponent */
- __u8 i; /* List index (when in range struct) */
-+ __u8 pad; /* Unused - just for alignement */
- };
-
- /*
-diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h
---- linux/include/net/iw_handler.14.h Mon Dec 2 18:51:17 2002
-+++ linux/include/net/iw_handler.h Mon Dec 2 18:54:51 2002
-@@ -1,7 +1,7 @@
- /*
- * This file define the new driver API for Wireless Extensions
- *
-- * Version : 3 17.1.02
-+ * Version : 4 21.6.02
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
-@@ -206,7 +206,7 @@
- * will be needed...
- * I just plan to increment with each new version.
- */
--#define IW_HANDLER_VERSION 3
-+#define IW_HANDLER_VERSION 4
-
- /*
- * Changes :
-@@ -217,6 +217,9 @@
- * - Add Wireless Event support :
- * o wireless_send_event() prototype
- * o iwe_stream_add_event/point() inline functions
-+ * V3 to V4
-+ * --------
-+ * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
- */
-
- /**************************** CONSTANTS ****************************/
-@@ -233,10 +236,10 @@
- #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
- #define IW_HEADER_TYPE_UINT 4 /* __u32 */
- #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
--#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */
--#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */
--#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */
--#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */
-+#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
-+#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
-+#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
-+#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
-
- /* Handling flags */
- /* Most are not implemented. I just use them as a reminder of some
-diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c
---- linux/net/core/wireless.14.c Mon Dec 2 18:51:35 2002
-+++ linux/net/core/wireless.c Mon Dec 2 18:53:10 2002
-@@ -33,8 +33,16 @@
- * o Propagate events as rtnetlink IFLA_WIRELESS option
- * o Generate event on selected SET requests
- *
-- * v4 - 18.04.01 - Jean II
-+ * v4 - 18.04.02 - Jean II
- * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
-+ *
-+ * v5 - 21.06.02 - Jean II
-+ * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
-+ * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
-+ * o Add IWEVCUSTOM for driver specific event/scanning token
-+ * o Turn on WE_STRICT_WRITE by default + kernel warning
-+ * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
-+ * o Fix off-by-one in test (extra_size <= IFNAMSIZ)
- */
-
- /***************************** INCLUDES *****************************/
-@@ -50,8 +58,9 @@
-
- /**************************** CONSTANTS ****************************/
-
--/* This will be turned on later on... */
--#undef WE_STRICT_WRITE /* Check write buffer size */
-+/* Enough lenience, let's make sure things are proper... */
-+#define WE_STRICT_WRITE /* Check write buffer size */
-+/* I'll probably drop both the define and kernel message in the next version */
-
- /* Debuging stuff */
- #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
-@@ -106,7 +115,7 @@ static const struct iw_ioctl_description
- /* SIOCSIWSPY */
- { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
- /* SIOCGIWSPY */
-- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
-+ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
- /* -- hole -- */
- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
- /* -- hole -- */
-@@ -176,25 +185,41 @@ static const struct iw_ioctl_description
- { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
- /* IWEVQUAL */
- { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
-+ /* IWEVCUSTOM */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
-+ /* IWEVREGISTERED */
-+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
-+ /* IWEVEXPIRED */
-+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
- };
- static const int standard_event_num = (sizeof(standard_event) /
- sizeof(struct iw_ioctl_description));
-
- /* Size (in bytes) of the various private data types */
--static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
-+static const char priv_type_size[] = {
-+ 0, /* IW_PRIV_TYPE_NONE */
-+ 1, /* IW_PRIV_TYPE_BYTE */
-+ 1, /* IW_PRIV_TYPE_CHAR */
-+ 0, /* Not defined */
-+ sizeof(__u32), /* IW_PRIV_TYPE_INT */
-+ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
-+ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
-+ 0, /* Not defined */
-+};
-
- /* Size (in bytes) of various events */
- static const int event_type_size[] = {
-- IW_EV_LCP_LEN,
-+ IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
-+ 0,
-+ IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
- 0,
-- IW_EV_CHAR_LEN,
-+ IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */
-+ IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
-+ IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
- 0,
-- IW_EV_UINT_LEN,
-- IW_EV_FREQ_LEN,
- IW_EV_POINT_LEN, /* Without variable payload */
-- IW_EV_PARAM_LEN,
-- IW_EV_ADDR_LEN,
-- IW_EV_QUAL_LEN,
-+ IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
-+ IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
- };
-
- /************************ COMMON SUBROUTINES ************************/
-@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s
- return -EFAULT;
- #ifdef WE_STRICT_WRITE
- /* Check if there is enough buffer up there */
-- if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
-+ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
-+ printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
- return -E2BIG;
-+ }
- #endif /* WE_STRICT_WRITE */
-
- /* Set the number of available ioctls. */
-@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st
- const struct iw_ioctl_description * descr;
- struct iw_request_info info;
- int ret = -EINVAL;
-+ int user_size = 0;
-
- /* Get the description of the IOCTL */
- if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
-@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st
- /* Check NULL pointer */
- if(iwr->u.data.pointer == NULL)
- return -EFAULT;
--#ifdef WE_STRICT_WRITE
-- /* Check if there is enough buffer up there */
-- if(iwr->u.data.length < descr->max_tokens)
-- return -E2BIG;
--#endif /* WE_STRICT_WRITE */
-+ /* Save user space buffer size for checking */
-+ user_size = iwr->u.data.length;
- }
-
- #ifdef WE_IOCTL_DEBUG
-@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st
-
- /* If we have something to return to the user */
- if (!ret && IW_IS_GET(cmd)) {
-+#ifdef WE_STRICT_WRITE
-+ /* Check if there is enough buffer up there */
-+ if(user_size < iwr->u.data.length) {
-+ printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
-+ kfree(extra);
-+ return -E2BIG;
-+ }
-+#endif /* WE_STRICT_WRITE */
-+
- err = copy_to_user(iwr->u.data.pointer, extra,
- iwr->u.data.length *
- descr->token_size);
-@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str
- /* Compute the size of the set/get arguments */
- if(descr != NULL) {
- if(IW_IS_SET(cmd)) {
-+ int offset = 0; /* For sub-ioctls */
-+ /* Check for sub-ioctl handler */
-+ if(descr->name[0] == '\0')
-+ /* Reserve one int for sub-ioctl index */
-+ offset = sizeof(__u32);
-+
- /* Size of set arguments */
- extra_size = get_priv_size(descr->set_args);
-
- /* Does it fits in iwr ? */
- if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-- (extra_size < IFNAMSIZ))
-+ ((extra_size + offset) <= IFNAMSIZ))
- extra_size = 0;
- } else {
- /* Size of set arguments */
-@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str
-
- /* Does it fits in iwr ? */
- if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-- (extra_size < IFNAMSIZ))
-+ (extra_size <= IFNAMSIZ))
- extra_size = 0;
- }
- }
-@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi
- * The best the driver could do is to log an error message.
- * We will do it ourselves instead...
- */
-- printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
-+ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
- dev->name, cmd);
- return;
- }
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff
deleted file mode 100644
index a27a7654a9..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff
+++ /dev/null
@@ -1,1513 +0,0 @@
-diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h
---- linux/include/linux-w12/netdevice.h Thu Nov 22 11:47:09 2001
-+++ linux/include/linux/netdevice.h Thu Jan 17 12:00:39 2002
-@@ -278,6 +278,10 @@ struct net_device
- struct net_device_stats* (*get_stats)(struct net_device *dev);
- struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
-
-+ /* List of functions to handle Wireless Extensions (instead of ioctl).
-+ * See <net/iw_handler.h> for details. Jean II */
-+ struct iw_handler_def * wireless_handlers;
-+
- /*
- * This marks the end of the "visible" part of the structure. All
- * fields hereafter are internal to the system, and may change at
-diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h
---- linux/include/linux-w12/wireless.h Thu Nov 22 11:47:12 2001
-+++ linux/include/linux/wireless.h Thu Jan 17 12:04:08 2002
-@@ -1,9 +1,10 @@
- /*
- * This file define a set of standard wireless extensions
- *
-- * Version : 12 5.10.01
-+ * Version : 13 6.12.01
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
- */
-
- #ifndef _LINUX_WIRELESS_H
-@@ -11,6 +12,8 @@
-
- /************************** DOCUMENTATION **************************/
- /*
-+ * Initial APIs (1996 -> onward) :
-+ * -----------------------------
- * Basically, the wireless extensions are for now a set of standard ioctl
- * call + /proc/net/wireless
- *
-@@ -27,16 +30,27 @@
- * We have the list of command plus a structure descibing the
- * data exchanged...
- * Note that to add these ioctl, I was obliged to modify :
-- * net/core/dev.c (two place + add include)
-- * net/ipv4/af_inet.c (one place + add include)
-+ * # net/core/dev.c (two place + add include)
-+ * # net/ipv4/af_inet.c (one place + add include)
- *
- * /proc/net/wireless is a copy of /proc/net/dev.
- * We have a structure for data passed from the driver to /proc/net/wireless
- * Too add this, I've modified :
-- * net/core/dev.c (two other places)
-- * include/linux/netdevice.h (one place)
-- * include/linux/proc_fs.h (one place)
-+ * # net/core/dev.c (two other places)
-+ * # include/linux/netdevice.h (one place)
-+ * # include/linux/proc_fs.h (one place)
-+ *
-+ * New driver API (2001 -> onward) :
-+ * -------------------------------
-+ * This file is only concerned with the user space API and common definitions.
-+ * The new driver API is defined and documented in :
-+ * # include/net/iw_handler.h
- *
-+ * Note as well that /proc/net/wireless implementation has now moved in :
-+ * # include/linux/wireless.c
-+ *
-+ * Other comments :
-+ * --------------
- * Do not add here things that are redundant with other mechanisms
- * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
- * wireless specific.
-@@ -54,16 +68,14 @@
- #include <linux/socket.h> /* for "struct sockaddr" et al */
- #include <linux/if.h> /* for IFNAMSIZ and co... */
-
--/**************************** CONSTANTS ****************************/
--
--/* --------------------------- VERSION --------------------------- */
-+/***************************** VERSION *****************************/
- /*
- * This constant is used to know the availability of the wireless
- * extensions and to know which version of wireless extensions it is
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
--#define WIRELESS_EXT 12
-+#define WIRELESS_EXT 13
-
- /*
- * Changes :
-@@ -123,12 +135,20 @@
- * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
- * - Add new statistics (frag, retry, beacon)
- * - Add average quality (for user space calibration)
-+ *
-+ * V12 to V13
-+ * ----------
-+ * - Document creation of new driver API.
-+ * - Extract union iwreq_data from struct iwreq (for new driver API).
-+ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT
- */
-
-+/**************************** CONSTANTS ****************************/
-+
- /* -------------------------- IOCTL LIST -------------------------- */
-
- /* Basic operations */
--#define SIOCSIWNAME 0x8B00 /* Unused */
-+#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */
- #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
- #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */
- #define SIOCGIWNWID 0x8B03 /* get network id */
-@@ -414,13 +434,49 @@ struct iw_statistics
-
- /* ------------------------ IOCTL REQUEST ------------------------ */
- /*
-+ * This structure defines the payload of an ioctl, and is used
-+ * below.
-+ *
-+ * Note that this structure should fit on the memory footprint
-+ * of iwreq (which is the same as ifreq), which mean a max size of
-+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
-+ * You should check this when increasing the structures defined
-+ * above in this file...
-+ */
-+union iwreq_data
-+{
-+ /* Config - generic */
-+ char name[IFNAMSIZ];
-+ /* Name : used to verify the presence of wireless extensions.
-+ * Name of the protocol/provider... */
-+
-+ struct iw_point essid; /* Extended network name */
-+ struct iw_param nwid; /* network id (or domain - the cell) */
-+ struct iw_freq freq; /* frequency or channel :
-+ * 0-1000 = channel
-+ * > 1000 = frequency in Hz */
-+
-+ struct iw_param sens; /* signal level threshold */
-+ struct iw_param bitrate; /* default bit rate */
-+ struct iw_param txpower; /* default transmit power */
-+ struct iw_param rts; /* RTS threshold threshold */
-+ struct iw_param frag; /* Fragmentation threshold */
-+ __u32 mode; /* Operation mode */
-+ struct iw_param retry; /* Retry limits & lifetime */
-+
-+ struct iw_point encoding; /* Encoding stuff : tokens */
-+ struct iw_param power; /* PM duration/timeout */
-+
-+ struct sockaddr ap_addr; /* Access point address */
-+
-+ struct iw_point data; /* Other large parameters */
-+};
-+
-+/*
- * The structure to exchange data for ioctl.
- * This structure is the same as 'struct ifreq', but (re)defined for
- * convenience...
-- *
-- * Note that it should fit on the same memory footprint !
-- * You should check this when increasing the above structures (16 octets)
-- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
-+ * Do I need to remind you about structure size (32 octets) ?
- */
- struct iwreq
- {
-@@ -429,35 +485,8 @@ struct iwreq
- char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
- } ifr_ifrn;
-
-- /* Data part */
-- union
-- {
-- /* Config - generic */
-- char name[IFNAMSIZ];
-- /* Name : used to verify the presence of wireless extensions.
-- * Name of the protocol/provider... */
--
-- struct iw_point essid; /* Extended network name */
-- struct iw_param nwid; /* network id (or domain - the cell) */
-- struct iw_freq freq; /* frequency or channel :
-- * 0-1000 = channel
-- * > 1000 = frequency in Hz */
--
-- struct iw_param sens; /* signal level threshold */
-- struct iw_param bitrate; /* default bit rate */
-- struct iw_param txpower; /* default transmit power */
-- struct iw_param rts; /* RTS threshold threshold */
-- struct iw_param frag; /* Fragmentation threshold */
-- __u32 mode; /* Operation mode */
-- struct iw_param retry; /* Retry limits & lifetime */
--
-- struct iw_point encoding; /* Encoding stuff : tokens */
-- struct iw_param power; /* PM duration/timeout */
--
-- struct sockaddr ap_addr; /* Access point address */
--
-- struct iw_point data; /* Other large parameters */
-- } u;
-+ /* Data part (defined just above) */
-+ union iwreq_data u;
- };
-
- /* -------------------------- IOCTL DATA -------------------------- */
-diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h
---- linux/include/net-w12/iw_handler.h Wed Dec 31 16:00:00 1969
-+++ linux/include/net/iw_handler.h Thu Jan 17 12:16:46 2002
-@@ -0,0 +1,374 @@
-+/*
-+ * This file define the new driver API for Wireless Extensions
-+ *
-+ * Version : 2 6.12.01
-+ *
-+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-+ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
-+ */
-+
-+#ifndef _IW_HANDLER_H
-+#define _IW_HANDLER_H
-+
-+/************************** DOCUMENTATION **************************/
-+/*
-+ * Initial driver API (1996 -> onward) :
-+ * -----------------------------------
-+ * The initial API just sends the IOCTL request received from user space
-+ * to the driver (via the driver ioctl handler). The driver has to
-+ * handle all the rest...
-+ *
-+ * The initial API also defines a specific handler in struct net_device
-+ * to handle wireless statistics.
-+ *
-+ * The initial APIs served us well and has proven a reasonably good design.
-+ * However, there is a few shortcommings :
-+ * o No events, everything is a request to the driver.
-+ * o Large ioctl function in driver with gigantic switch statement
-+ * (i.e. spaghetti code).
-+ * o Driver has to mess up with copy_to/from_user, and in many cases
-+ * does it unproperly. Common mistakes are :
-+ * * buffer overflows (no checks or off by one checks)
-+ * * call copy_to/from_user with irq disabled
-+ * o The user space interface is tied to ioctl because of the use
-+ * copy_to/from_user.
-+ *
-+ * New driver API (2001 -> onward) :
-+ * -------------------------------
-+ * The new driver API is just a bunch of standard functions (handlers),
-+ * each handling a specific Wireless Extension. The driver just export
-+ * the list of handler it supports, and those will be called apropriately.
-+ *
-+ * I tried to keep the main advantage of the previous API (simplicity,
-+ * efficiency and light weight), and also I provide a good dose of backward
-+ * compatibility (most structures are the same, driver can use both API
-+ * simultaneously, ...).
-+ * Hopefully, I've also addressed the shortcomming of the initial API.
-+ *
-+ * The advantage of the new API are :
-+ * o Handling of Extensions in driver broken in small contained functions
-+ * o Tighter checks of ioctl before calling the driver
-+ * o Flexible commit strategy (at least, the start of it)
-+ * o Backward compatibility (can be mixed with old API)
-+ * o Driver doesn't have to worry about memory and user-space issues
-+ * The last point is important for the following reasons :
-+ * o You are now able to call the new driver API from any API you
-+ * want (including from within other parts of the kernel).
-+ * o Common mistakes are avoided (buffer overflow, user space copy
-+ * with irq disabled and so on).
-+ *
-+ * The Drawback of the new API are :
-+ * o bloat (especially kernel)
-+ * o need to migrate existing drivers to new API
-+ * My initial testing shows that the new API adds around 3kB to the kernel
-+ * and save between 0 and 5kB from a typical driver.
-+ * Also, as all structures and data types are unchanged, the migration is
-+ * quite straightforward (but tedious).
-+ *
-+ * ---
-+ *
-+ * The new driver API is defined below in this file. User space should
-+ * not be aware of what's happening down there...
-+ *
-+ * A new kernel wrapper is in charge of validating the IOCTLs and calling
-+ * the appropriate driver handler. This is implemented in :
-+ * # net/core/wireless.c
-+ *
-+ * The driver export the list of handlers in :
-+ * # include/linux/netdevice.h (one place)
-+ *
-+ * The new driver API is available for WIRELESS_EXT >= 13.
-+ * Good luck with migration to the new API ;-)
-+ */
-+
-+/* ---------------------- THE IMPLEMENTATION ---------------------- */
-+/*
-+ * Some of the choice I've made are pretty controversials. Defining an
-+ * API is very much weighting compromises. This goes into some of the
-+ * details and the thinking behind the implementation.
-+ *
-+ * Implementation goals :
-+ * --------------------
-+ * The implementation goals were as follow :
-+ * o Obvious : you should not need a PhD to understand what's happening,
-+ * the benefit is easier maintainance.
-+ * o Flexible : it should accomodate a wide variety of driver
-+ * implementations and be as flexible as the old API.
-+ * o Lean : it should be efficient memory wise to minimise the impact
-+ * on kernel footprint.
-+ * o Transparent to user space : the large number of user space
-+ * applications that use Wireless Extensions should not need
-+ * any modifications.
-+ *
-+ * Array of functions versus Struct of functions
-+ * ---------------------------------------------
-+ * 1) Having an array of functions allow the kernel code to access the
-+ * handler in a single lookup, which is much more efficient (think hash
-+ * table here).
-+ * 2) The only drawback is that driver writer may put their handler in
-+ * the wrong slot. This is trivial to test (I set the frequency, the
-+ * bitrate changes). Once the handler is in the proper slot, it will be
-+ * there forever, because the array is only extended at the end.
-+ * 3) Backward/forward compatibility : adding new handler just require
-+ * extending the array, so you can put newer driver in older kernel
-+ * without having to patch the kernel code (and vice versa).
-+ *
-+ * All handler are of the same generic type
-+ * ----------------------------------------
-+ * That's a feature !!!
-+ * 1) Having a generic handler allow to have generic code, which is more
-+ * efficient. If each of the handler was individually typed I would need
-+ * to add a big switch in the kernel (== more bloat). This solution is
-+ * more scalable, adding new Wireless Extensions doesn't add new code.
-+ * 2) You can use the same handler in different slots of the array. For
-+ * hardware, it may be more efficient or logical to handle multiple
-+ * Wireless Extensions with a single function, and the API allow you to
-+ * do that. (An example would be a single record on the card to control
-+ * both bitrate and frequency, the handler would read the old record,
-+ * modify it according to info->cmd and rewrite it).
-+ *
-+ * Functions prototype uses union iwreq_data
-+ * -----------------------------------------
-+ * Some would have prefered functions defined this way :
-+ * static int mydriver_ioctl_setrate(struct net_device *dev,
-+ * long rate, int auto)
-+ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
-+ * can't do it (different hardware may have different notion of what a
-+ * valid frequency is), so we don't pretend that we do it.
-+ * 2) The above form is not extendable. If I want to add a flag (for
-+ * example to distinguish setting max rate and basic rate), I would
-+ * break the prototype. Using iwreq_data is more flexible.
-+ * 3) Also, the above form is not generic (see above).
-+ * 4) I don't expect driver developper using the wrong field of the
-+ * union (Doh !), so static typechecking doesn't add much value.
-+ * 5) Lastly, you can skip the union by doing :
-+ * static int mydriver_ioctl_setrate(struct net_device *dev,
-+ * struct iw_request_info *info,
-+ * struct iw_param *rrq,
-+ * char *extra)
-+ * And then adding the handler in the array like this :
-+ * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE
-+ *
-+ * Using functions and not a registry
-+ * ----------------------------------
-+ * Another implementation option would have been for every instance to
-+ * define a registry (a struct containing all the Wireless Extensions)
-+ * and only have a function to commit the registry to the hardware.
-+ * 1) This approach can be emulated by the current code, but not
-+ * vice versa.
-+ * 2) Some drivers don't keep any configuration in the driver, for them
-+ * adding such a registry would be a significant bloat.
-+ * 3) The code to translate from Wireless Extension to native format is
-+ * needed anyway, so it would not reduce significantely the amount of code.
-+ * 4) The current approach only selectively translate Wireless Extensions
-+ * to native format and only selectively set, whereas the registry approach
-+ * would require to translate all WE and set all parameters for any single
-+ * change.
-+ * 5) For many Wireless Extensions, the GET operation return the current
-+ * dynamic value, not the value that was set.
-+ *
-+ * This header is <net/iw_handler.h>
-+ * ---------------------------------
-+ * 1) This header is kernel space only and should not be exported to
-+ * user space. Headers in "include/linux/" are exported, headers in
-+ * "include/net/" are not.
-+ *
-+ * Mixed 32/64 bit issues
-+ * ----------------------
-+ * The Wireless Extensions are designed to be 64 bit clean, by using only
-+ * datatypes with explicit storage size.
-+ * There are some issues related to kernel and user space using different
-+ * memory model, and in particular 64bit kernel with 32bit user space.
-+ * The problem is related to struct iw_point, that contains a pointer
-+ * that *may* need to be translated.
-+ * This is quite messy. The new API doesn't solve this problem (it can't),
-+ * but is a step in the right direction :
-+ * 1) Meta data about each ioctl is easily available, so we know what type
-+ * of translation is needed.
-+ * 2) The move of data between kernel and user space is only done in a single
-+ * place in the kernel, so adding specific hooks in there is possible.
-+ * 3) In the long term, it allows to move away from using ioctl as the
-+ * user space API.
-+ *
-+ * So many comments and so few code
-+ * --------------------------------
-+ * That's a feature. Comments won't bloat the resulting kernel binary.
-+ */
-+
-+/***************************** INCLUDES *****************************/
-+
-+#include <linux/wireless.h> /* IOCTL user space API */
-+
-+/***************************** VERSION *****************************/
-+/*
-+ * This constant is used to know which version of the driver API is
-+ * available. Hopefully, this will be pretty stable and no changes
-+ * will be needed...
-+ * I just plan to increment with each new version.
-+ */
-+#define IW_HANDLER_VERSION 2
-+
-+/**************************** CONSTANTS ****************************/
-+
-+/* Special error message for the driver to indicate that we
-+ * should do a commit after return from the iw_handler */
-+#define EIWCOMMIT EINPROGRESS
-+
-+/* Flags available in struct iw_request_info */
-+#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */
-+
-+/* Type of headers we know about (basically union iwreq_data) */
-+#define IW_HEADER_TYPE_NULL 0 /* Not available */
-+#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
-+#define IW_HEADER_TYPE_UINT 4 /* __u32 */
-+#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
-+#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */
-+#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */
-+#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */
-+
-+/* Handling flags */
-+/* Most are not implemented. I just use them as a reminder of some
-+ * cool features we might need one day ;-) */
-+#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
-+/* Wrapper level flags */
-+#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
-+#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
-+#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */
-+/* Driver level flags */
-+#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
-+
-+/****************************** TYPES ******************************/
-+
-+/* ----------------------- WIRELESS HANDLER ----------------------- */
-+/*
-+ * A wireless handler is just a standard function, that looks like the
-+ * ioctl handler.
-+ * We also define there how a handler list look like... As the Wireless
-+ * Extension space is quite dense, we use a simple array, which is faster
-+ * (that's the perfect hash table ;-).
-+ */
-+
-+/*
-+ * Meta data about the request passed to the iw_handler.
-+ * Most handlers can safely ignore what's in there.
-+ * The 'cmd' field might come handy if you want to use the same handler
-+ * for multiple command...
-+ * This struct is also my long term insurance. I can add new fields here
-+ * without breaking the prototype of iw_handler...
-+ */
-+struct iw_request_info
-+{
-+ __u16 cmd; /* Wireless Extension command */
-+ __u16 flags; /* More to come ;-) */
-+};
-+
-+/*
-+ * This is how a function handling a Wireless Extension should look
-+ * like (both get and set, standard and private).
-+ */
-+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
-+ union iwreq_data *wrqu, char *extra);
-+
-+/*
-+ * This define all the handler that the driver export.
-+ * As you need only one per driver type, please use a static const
-+ * shared by all driver instances... Same for the members...
-+ * This will be linked from net_device in <linux/netdevice.h>
-+ */
-+struct iw_handler_def
-+{
-+ /* Number of handlers defined (more precisely, index of the
-+ * last defined handler + 1) */
-+ __u16 num_standard;
-+ __u16 num_private;
-+ /* Number of private arg description */
-+ __u16 num_private_args;
-+
-+ /* Array of handlers for standard ioctls
-+ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
-+ */
-+ iw_handler * standard;
-+
-+ /* Array of handlers for private ioctls
-+ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
-+ */
-+ iw_handler * private;
-+
-+ /* Arguments of private handler. This one is just a list, so you
-+ * can put it in any order you want and should not leave holes...
-+ * We will automatically export that to user space... */
-+ struct iw_priv_args * private_args;
-+
-+ /* In the long term, get_wireless_stats will move from
-+ * 'struct net_device' to here, to minimise bloat. */
-+};
-+
-+/* ----------------------- WIRELESS EVENTS ----------------------- */
-+/*
-+ * Currently we don't support events, so let's just plan for the
-+ * future...
-+ */
-+
-+/*
-+ * A Wireless Event.
-+ */
-+// How do we define short header ? We don't want a flag on length.
-+// Probably a flag on event ? Highest bit to zero...
-+struct iw_event
-+{
-+ __u16 length; /* Lenght of this stuff */
-+ __u16 event; /* Wireless IOCTL */
-+ union iwreq_data header; /* IOCTL fixed payload */
-+ char extra[0]; /* Optional IOCTL data */
-+};
-+
-+/* ---------------------- IOCTL DESCRIPTION ---------------------- */
-+/*
-+ * One of the main goal of the new interface is to deal entirely with
-+ * user space/kernel space memory move.
-+ * For that, we need to know :
-+ * o if iwreq is a pointer or contain the full data
-+ * o what is the size of the data to copy
-+ *
-+ * For private IOCTLs, we use the same rules as used by iwpriv and
-+ * defined in struct iw_priv_args.
-+ *
-+ * For standard IOCTLs, things are quite different and we need to
-+ * use the stuctures below. Actually, this struct is also more
-+ * efficient, but that's another story...
-+ */
-+
-+/*
-+ * Describe how a standard IOCTL looks like.
-+ */
-+struct iw_ioctl_description
-+{
-+ __u8 header_type; /* NULL, iw_point or other */
-+ __u8 token_type; /* Future */
-+ __u16 token_size; /* Granularity of payload */
-+ __u16 min_tokens; /* Min acceptable token number */
-+ __u16 max_tokens; /* Max acceptable token number */
-+ __u32 flags; /* Special handling of the request */
-+};
-+
-+/* Need to think of short header translation table. Later. */
-+
-+/**************************** PROTOTYPES ****************************/
-+/*
-+ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
-+ * Those may be called only within the kernel.
-+ */
-+
-+/* First : function strictly used inside the kernel */
-+
-+/* Handle /proc/net/wireless, called in net/code/dev.c */
-+extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-+ int length);
-+
-+/* Handle IOCTLs, called in net/code/dev.c */
-+extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
-+
-+/* Second : functions that may be called by driver modules */
-+/* None yet */
-+
-+#endif /* _LINUX_WIRELESS_H */
-diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile
---- linux/net/core-w12/Makefile Tue Oct 30 15:08:12 2001
-+++ linux/net/core/Makefile Thu Jan 17 11:06:07 2002
-@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d
- obj-$(CONFIG_NETFILTER) += netfilter.o
- obj-$(CONFIG_NET_DIVERT) += dv.o
- obj-$(CONFIG_NET_PROFILE) += profile.o
-+obj-$(CONFIG_NET_RADIO) += wireless.o
-+# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
-+obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
-
- include $(TOPDIR)/Rules.make
-diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c
---- linux/net/core-w12/dev.c Wed Nov 7 14:39:36 2001
-+++ linux/net/core/dev.c Thu Jan 17 11:06:07 2002
-@@ -102,6 +102,7 @@
- #include <linux/module.h>
- #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
- #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
-+#include <net/iw_handler.h>
- #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
- #ifdef CONFIG_PLIP
- extern int plip_init(void);
-@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer,
- #endif /* CONFIG_PROC_FS */
-
-
--#ifdef WIRELESS_EXT
--#ifdef CONFIG_PROC_FS
--
--/*
-- * Print one entry of /proc/net/wireless
-- * This is a clone of /proc/net/dev (just above)
-- */
--static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
--{
-- /* Get stats from the driver */
-- struct iw_statistics *stats = (dev->get_wireless_stats ?
-- dev->get_wireless_stats(dev) :
-- (struct iw_statistics *) NULL);
-- int size;
--
-- if (stats != (struct iw_statistics *) NULL) {
-- size = sprintf(buffer,
-- "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n",
-- dev->name,
-- stats->status,
-- stats->qual.qual,
-- stats->qual.updated & 1 ? '.' : ' ',
-- stats->qual.level,
-- stats->qual.updated & 2 ? '.' : ' ',
-- stats->qual.noise,
-- stats->qual.updated & 4 ? '.' : ' ',
-- stats->discard.nwid,
-- stats->discard.code,
-- stats->discard.fragment,
-- stats->discard.retries,
-- stats->discard.misc,
-- stats->miss.beacon);
-- stats->qual.updated = 0;
-- }
-- else
-- size = 0;
--
-- return size;
--}
--
--/*
-- * Print info for /proc/net/wireless (print all entries)
-- * This is a clone of /proc/net/dev (just above)
-- */
--static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-- int length)
--{
-- int len = 0;
-- off_t begin = 0;
-- off_t pos = 0;
-- int size;
--
-- struct net_device * dev;
--
-- size = sprintf(buffer,
-- "Inter-| sta-| Quality | Discarded packets | Missed\n"
-- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n"
-- );
--
-- pos += size;
-- len += size;
--
-- read_lock(&dev_base_lock);
-- for (dev = dev_base; dev != NULL; dev = dev->next) {
-- size = sprintf_wireless_stats(buffer + len, dev);
-- len += size;
-- pos = begin + len;
--
-- if (pos < offset) {
-- len = 0;
-- begin = pos;
-- }
-- if (pos > offset + length)
-- break;
-- }
-- read_unlock(&dev_base_lock);
--
-- *start = buffer + (offset - begin); /* Start of wanted data */
-- len -= (offset - begin); /* Start slop */
-- if (len > length)
-- len = length; /* Ending slop */
-- if (len < 0)
-- len = 0;
--
-- return len;
--}
--#endif /* CONFIG_PROC_FS */
--
--/*
-- * Allow programatic access to /proc/net/wireless even if /proc
-- * doesn't exist... Also more efficient...
-- */
--static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
--{
-- /* Get stats from the driver */
-- struct iw_statistics *stats = (dev->get_wireless_stats ?
-- dev->get_wireless_stats(dev) :
-- (struct iw_statistics *) NULL);
--
-- if (stats != (struct iw_statistics *) NULL) {
-- struct iwreq * wrq = (struct iwreq *)ifr;
--
-- /* Copy statistics to the user buffer */
-- if(copy_to_user(wrq->u.data.pointer, stats,
-- sizeof(struct iw_statistics)))
-- return -EFAULT;
--
-- /* Check if we need to clear the update flag */
-- if(wrq->u.data.flags != 0)
-- stats->qual.updated = 0;
-- return(0);
-- } else
-- return -EOPNOTSUPP;
--}
--#endif /* WIRELESS_EXT */
--
- /**
- * netdev_set_master - set up master/slave pair
- * @slave: slave device
-@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr,
- notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
- return 0;
-
--#ifdef WIRELESS_EXT
-- case SIOCGIWSTATS:
-- return dev_iwstats(dev, ifr);
--#endif /* WIRELESS_EXT */
--
- /*
- * Unknown or private ioctl
- */
-@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr,
- return -EOPNOTSUPP;
- }
-
--#ifdef WIRELESS_EXT
-- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-- if (dev->do_ioctl) {
-- if (!netif_device_present(dev))
-- return -ENODEV;
-- return dev->do_ioctl(dev, ifr, cmd);
-- }
-- return -EOPNOTSUPP;
-- }
--#endif /* WIRELESS_EXT */
--
- }
- return -EINVAL;
- }
-@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar
- }
- dev_load(ifr.ifr_name);
- rtnl_lock();
-- ret = dev_ifsioc(&ifr, cmd);
-+ /* Follow me in net/core/wireless.c */
-+ ret = wireless_process_ioctl(&ifr, cmd);
- rtnl_unlock();
- if (!ret && IW_IS_GET(cmd) &&
- copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-@@ -2856,6 +2726,7 @@ int __init net_dev_init(void)
- proc_net_create("dev", 0, dev_get_info);
- create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
- #ifdef WIRELESS_EXT
-+ /* Available in net/core/wireless.c */
- proc_net_create("wireless", 0, dev_get_wireless_info);
- #endif /* WIRELESS_EXT */
- #endif /* CONFIG_PROC_FS */
-diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c
---- linux/net/core-w12/wireless.c Wed Dec 31 16:00:00 1969
-+++ linux/net/core/wireless.c Mon Jan 21 11:13:23 2002
-@@ -0,0 +1,733 @@
-+/*
-+ * This file implement the Wireless Extensions APIs.
-+ *
-+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
-+ *
-+ * (As all part of the Linux kernel, this file is GPL)
-+ */
-+
-+/************************** DOCUMENTATION **************************/
-+/*
-+ * API definition :
-+ * --------------
-+ * See <linux/wireless.h> for details of the APIs and the rest.
-+ *
-+ * History :
-+ * -------
-+ *
-+ * v1 - 5.12.01 - Jean II
-+ * o Created this file.
-+ *
-+ * v2 - 13.12.01 - Jean II
-+ * o Move /proc/net/wireless stuff from net/core/dev.c to here
-+ * o Make Wireless Extension IOCTLs go through here
-+ * o Added iw_handler handling ;-)
-+ * o Added standard ioctl description
-+ * o Initial dumb commit strategy based on orinoco.c
-+ */
-+
-+/***************************** INCLUDES *****************************/
-+
-+#include <asm/uaccess.h> /* copy_to_user() */
-+#include <linux/config.h> /* Not needed ??? */
-+#include <linux/types.h> /* off_t */
-+#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
-+
-+#include <linux/wireless.h> /* Pretty obvious */
-+#include <net/iw_handler.h> /* New driver API */
-+
-+/**************************** CONSTANTS ****************************/
-+
-+/* This will be turned on later on... */
-+#undef WE_STRICT_WRITE /* Check write buffer size */
-+
-+/* Debuging stuff */
-+#undef WE_IOCTL_DEBUG /* Debug IOCTL API */
-+
-+/************************* GLOBAL VARIABLES *************************/
-+/*
-+ * You should not use global variables, because or re-entrancy.
-+ * On our case, it's only const, so it's OK...
-+ */
-+static const struct iw_ioctl_description standard_ioctl[] = {
-+ /* SIOCSIWCOMMIT (internal) */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCGIWNAME */
-+ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWNWID */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
-+ /* SIOCGIWNWID */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWFREQ */
-+ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
-+ /* SIOCGIWFREQ */
-+ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWMODE */
-+ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
-+ /* SIOCGIWMODE */
-+ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWSENS */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWSENS */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCSIWRANGE */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCGIWRANGE */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWPRIV */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCGIWPRIV (handled directly by us) */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCSIWSTATS */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCGIWSTATS (handled directly by us) */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWSPY */
-+ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
-+ /* SIOCGIWSPY */
-+ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCSIWAP */
-+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
-+ /* SIOCGIWAP */
-+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCGIWAPLIST */
-+ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCSIWESSID */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
-+ /* SIOCGIWESSID */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
-+ /* SIOCSIWNICKN */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
-+ /* SIOCGIWNICKN */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* -- hole -- */
-+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCSIWRATE */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWRATE */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCSIWRTS */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWRTS */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCSIWFRAG */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWFRAG */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCSIWTXPOW */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWTXPOW */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCSIWRETRY */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWRETRY */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCSIWENCODE */
-+ { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
-+ /* SIOCGIWENCODE */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
-+ /* SIOCSIWPOWER */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWPOWER */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+};
-+
-+/* Size (in bytes) of the various private data types */
-+char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
-+
-+/************************ COMMON SUBROUTINES ************************/
-+/*
-+ * Stuff that may be used in various place or doesn't fit in one
-+ * of the section below.
-+ */
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Return the driver handler associated with a specific Wireless Extension.
-+ * Called from various place, so make sure it remains efficient.
-+ */
-+static inline iw_handler get_handler(struct net_device *dev,
-+ unsigned int cmd)
-+{
-+ unsigned int index; /* MUST be unsigned */
-+
-+ /* Check if we have some wireless handlers defined */
-+ if(dev->wireless_handlers == NULL)
-+ return NULL;
-+
-+ /* Try as a standard command */
-+ index = cmd - SIOCIWFIRST;
-+ if(index < dev->wireless_handlers->num_standard)
-+ return dev->wireless_handlers->standard[index];
-+
-+ /* Try as a private command */
-+ index = cmd - SIOCIWFIRSTPRIV;
-+ if(index < dev->wireless_handlers->num_private)
-+ return dev->wireless_handlers->private[index];
-+
-+ /* Not found */
-+ return NULL;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Get statistics out of the driver
-+ */
-+static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
-+{
-+ return (dev->get_wireless_stats ?
-+ dev->get_wireless_stats(dev) :
-+ (struct iw_statistics *) NULL);
-+ /* In the future, get_wireless_stats may move from 'struct net_device'
-+ * to 'struct iw_handler_def', to de-bloat struct net_device.
-+ * Definitely worse a thought... */
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Call the commit handler in the driver
-+ * (if exist and if conditions are right)
-+ *
-+ * Note : our current commit strategy is currently pretty dumb,
-+ * but we will be able to improve on that...
-+ * The goal is to try to agreagate as many changes as possible
-+ * before doing the commit. Drivers that will define a commit handler
-+ * are usually those that need a reset after changing parameters, so
-+ * we want to minimise the number of reset.
-+ * A cool idea is to use a timer : at each "set" command, we re-set the
-+ * timer, when the timer eventually fires, we call the driver.
-+ * Hopefully, more on that later.
-+ *
-+ * Also, I'm waiting to see how many people will complain about the
-+ * netif_running(dev) test. I'm open on that one...
-+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
-+ */
-+static inline int call_commit_handler(struct net_device * dev)
-+{
-+ if((netif_running(dev)) &&
-+ (dev->wireless_handlers->standard[0] != NULL)) {
-+ /* Call the commit handler on the driver */
-+ return dev->wireless_handlers->standard[0](dev, NULL,
-+ NULL, NULL);
-+ } else
-+ return 0; /* Command completed successfully */
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Number of private arguments
-+ */
-+static inline int get_priv_size(__u16 args)
-+{
-+ int num = args & IW_PRIV_SIZE_MASK;
-+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
-+
-+ return num * priv_type_size[type];
-+}
-+
-+
-+/******************** /proc/net/wireless SUPPORT ********************/
-+/*
-+ * The /proc/net/wireless file is a human readable user-space interface
-+ * exporting various wireless specific statistics from the wireless devices.
-+ * This is the most popular part of the Wireless Extensions ;-)
-+ *
-+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
-+ * The content of the file is basically the content of "struct iw_statistics".
-+ */
-+
-+#ifdef CONFIG_PROC_FS
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Print one entry (line) of /proc/net/wireless
-+ */
-+static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
-+{
-+ /* Get stats from the driver */
-+ struct iw_statistics *stats;
-+ int size;
-+
-+ stats = get_wireless_stats(dev);
-+ if (stats != (struct iw_statistics *) NULL) {
-+ size = sprintf(buffer,
-+ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n",
-+ dev->name,
-+ stats->status,
-+ stats->qual.qual,
-+ stats->qual.updated & 1 ? '.' : ' ',
-+ stats->qual.level,
-+ stats->qual.updated & 2 ? '.' : ' ',
-+ stats->qual.noise,
-+ stats->qual.updated & 4 ? '.' : ' ',
-+ stats->discard.nwid,
-+ stats->discard.code,
-+ stats->discard.fragment,
-+ stats->discard.retries,
-+ stats->discard.misc,
-+ stats->miss.beacon);
-+ stats->qual.updated = 0;
-+ }
-+ else
-+ size = 0;
-+
-+ return size;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Print info for /proc/net/wireless (print all entries)
-+ */
-+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-+ int length)
-+{
-+ int len = 0;
-+ off_t begin = 0;
-+ off_t pos = 0;
-+ int size;
-+
-+ struct net_device * dev;
-+
-+ size = sprintf(buffer,
-+ "Inter-| sta-| Quality | Discarded packets | Missed\n"
-+ " face | tus | link level noise | nwid crypt frag retry misc | beacon\n"
-+ );
-+
-+ pos += size;
-+ len += size;
-+
-+ read_lock(&dev_base_lock);
-+ for (dev = dev_base; dev != NULL; dev = dev->next) {
-+ size = sprintf_wireless_stats(buffer + len, dev);
-+ len += size;
-+ pos = begin + len;
-+
-+ if (pos < offset) {
-+ len = 0;
-+ begin = pos;
-+ }
-+ if (pos > offset + length)
-+ break;
-+ }
-+ read_unlock(&dev_base_lock);
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ len -= (offset - begin); /* Start slop */
-+ if (len > length)
-+ len = length; /* Ending slop */
-+ if (len < 0)
-+ len = 0;
-+
-+ return len;
-+}
-+#endif /* CONFIG_PROC_FS */
-+
-+/************************** IOCTL SUPPORT **************************/
-+/*
-+ * The original user space API to configure all those Wireless Extensions
-+ * is through IOCTLs.
-+ * In there, we check if we need to call the new driver API (iw_handler)
-+ * or just call the driver ioctl handler.
-+ */
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Allow programatic access to /proc/net/wireless even if /proc
-+ * doesn't exist... Also more efficient...
-+ */
-+static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
-+{
-+ /* Get stats from the driver */
-+ struct iw_statistics *stats;
-+
-+ stats = get_wireless_stats(dev);
-+ if (stats != (struct iw_statistics *) NULL) {
-+ struct iwreq * wrq = (struct iwreq *)ifr;
-+
-+ /* Copy statistics to the user buffer */
-+ if(copy_to_user(wrq->u.data.pointer, stats,
-+ sizeof(struct iw_statistics)))
-+ return -EFAULT;
-+
-+ /* Check if we need to clear the update flag */
-+ if(wrq->u.data.flags != 0)
-+ stats->qual.updated = 0;
-+ return 0;
-+ } else
-+ return -EOPNOTSUPP;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Export the driver private handler definition
-+ * They will be picked up by tools like iwpriv...
-+ */
-+static inline int ioctl_export_private(struct net_device * dev,
-+ struct ifreq * ifr)
-+{
-+ struct iwreq * iwr = (struct iwreq *) ifr;
-+
-+ /* Check if the driver has something to export */
-+ if((dev->wireless_handlers->num_private_args == 0) ||
-+ (dev->wireless_handlers->private_args == NULL))
-+ return -EOPNOTSUPP;
-+
-+ /* Check NULL pointer */
-+ if(iwr->u.data.pointer == NULL)
-+ return -EFAULT;
-+#ifdef WE_STRICT_WRITE
-+ /* Check if there is enough buffer up there */
-+ if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
-+ return -E2BIG;
-+#endif /* WE_STRICT_WRITE */
-+
-+ /* Set the number of available ioctls. */
-+ iwr->u.data.length = dev->wireless_handlers->num_private_args;
-+
-+ /* Copy structure to the user buffer. */
-+ if (copy_to_user(iwr->u.data.pointer,
-+ dev->wireless_handlers->private_args,
-+ sizeof(struct iw_priv_args) * iwr->u.data.length))
-+ return -EFAULT;
-+
-+ return 0;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Wrapper to call a standard Wireless Extension handler.
-+ * We do various checks and also take care of moving data between
-+ * user space and kernel space.
-+ */
-+static inline int ioctl_standard_call(struct net_device * dev,
-+ struct ifreq * ifr,
-+ unsigned int cmd,
-+ iw_handler handler)
-+{
-+ struct iwreq * iwr = (struct iwreq *) ifr;
-+ const struct iw_ioctl_description * descr;
-+ struct iw_request_info info;
-+ int ret = -EINVAL;
-+
-+ /* Get the description of the IOCTL */
-+ descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-+
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
-+ ifr->ifr_name, cmd);
-+ printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-+#endif /* WE_IOCTL_DEBUG */
-+
-+ /* Prepare the call */
-+ info.cmd = cmd;
-+ info.flags = 0;
-+
-+ /* Check if we have a pointer to user space data or not */
-+ if(descr->header_type != IW_HEADER_TYPE_POINT) {
-+ /* No extra arguments. Trivial to handle */
-+ ret = handler(dev, &info, &(iwr->u), NULL);
-+ } else {
-+ char * extra;
-+ int err;
-+
-+ /* Check what user space is giving us */
-+ if(IW_IS_SET(cmd)) {
-+ /* Check NULL pointer */
-+ if((iwr->u.data.pointer == NULL) &&
-+ (iwr->u.data.length != 0))
-+ return -EFAULT;
-+ /* Check if number of token fits within bounds */
-+ if(iwr->u.data.length > descr->max_tokens)
-+ return -E2BIG;
-+ if(iwr->u.data.length < descr->min_tokens)
-+ return -EINVAL;
-+ } else {
-+ /* Check NULL pointer */
-+ if(iwr->u.data.pointer == NULL)
-+ return -EFAULT;
-+#ifdef WE_STRICT_WRITE
-+ /* Check if there is enough buffer up there */
-+ if(iwr->u.data.length < descr->max_tokens)
-+ return -E2BIG;
-+#endif /* WE_STRICT_WRITE */
-+ }
-+
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "Malloc %d bytes\n",
-+ descr->max_tokens * descr->token_size);
-+#endif /* WE_IOCTL_DEBUG */
-+
-+ /* Always allocate for max space. Easier, and won't last
-+ * long... */
-+ extra = kmalloc(descr->max_tokens * descr->token_size,
-+ GFP_KERNEL);
-+ if (extra == NULL) {
-+ return -ENOMEM;
-+ }
-+
-+ /* If it is a SET, get all the extra data in here */
-+ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-+ err = copy_from_user(extra, iwr->u.data.pointer,
-+ iwr->u.data.length *
-+ descr->token_size);
-+ if (err) {
-+ kfree(extra);
-+ return -EFAULT;
-+ }
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "Got %d bytes\n",
-+ iwr->u.data.length * descr->token_size);
-+#endif /* WE_IOCTL_DEBUG */
-+ }
-+
-+ /* Call the handler */
-+ ret = handler(dev, &info, &(iwr->u), extra);
-+
-+ /* If we have something to return to the user */
-+ if (!ret && IW_IS_GET(cmd)) {
-+ err = copy_to_user(iwr->u.data.pointer, extra,
-+ iwr->u.data.length *
-+ descr->token_size);
-+ if (err)
-+ ret = -EFAULT;
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "Wrote %d bytes\n",
-+ iwr->u.data.length * descr->token_size);
-+#endif /* WE_IOCTL_DEBUG */
-+ }
-+
-+ /* Cleanup - I told you it wasn't that long ;-) */
-+ kfree(extra);
-+ }
-+
-+ /* Call commit handler if needed and defined */
-+ if(ret == -EIWCOMMIT)
-+ ret = call_commit_handler(dev);
-+
-+ /* Here, we will generate the appropriate event if needed */
-+
-+ return ret;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Wrapper to call a private Wireless Extension handler.
-+ * We do various checks and also take care of moving data between
-+ * user space and kernel space.
-+ * It's not as nice and slimline as the standard wrapper. The cause
-+ * is struct iw_priv_args, which was not really designed for the
-+ * job we are going here.
-+ *
-+ * IMPORTANT : This function prevent to set and get data on the same
-+ * IOCTL and enforce the SET/GET convention. Not doing it would be
-+ * far too hairy...
-+ * If you need to set and get data at the same time, please don't use
-+ * a iw_handler but process it in your ioctl handler (i.e. use the
-+ * old driver API).
-+ */
-+static inline int ioctl_private_call(struct net_device * dev,
-+ struct ifreq * ifr,
-+ unsigned int cmd,
-+ iw_handler handler)
-+{
-+ struct iwreq * iwr = (struct iwreq *) ifr;
-+ struct iw_priv_args * descr = NULL;
-+ struct iw_request_info info;
-+ int extra_size = 0;
-+ int i;
-+ int ret = -EINVAL;
-+
-+ /* Get the description of the IOCTL */
-+ for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
-+ if(cmd == dev->wireless_handlers->private_args[i].cmd) {
-+ descr = &(dev->wireless_handlers->private_args[i]);
-+ break;
-+ }
-+
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
-+ ifr->ifr_name, cmd);
-+ if(descr) {
-+ printk(KERN_DEBUG "Name %s, set %X, get %X\n",
-+ descr->name, descr->set_args, descr->get_args);
-+ }
-+#endif /* WE_IOCTL_DEBUG */
-+
-+ /* Compute the size of the set/get arguments */
-+ if(descr != NULL) {
-+ if(IW_IS_SET(cmd)) {
-+ /* Size of set arguments */
-+ extra_size = get_priv_size(descr->set_args);
-+
-+ /* Does it fits in iwr ? */
-+ if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-+ (extra_size < IFNAMSIZ))
-+ extra_size = 0;
-+ } else {
-+ /* Size of set arguments */
-+ extra_size = get_priv_size(descr->get_args);
-+
-+ /* Does it fits in iwr ? */
-+ if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-+ (extra_size < IFNAMSIZ))
-+ extra_size = 0;
-+ }
-+ }
-+
-+ /* Prepare the call */
-+ info.cmd = cmd;
-+ info.flags = 0;
-+
-+ /* Check if we have a pointer to user space data or not. */
-+ if(extra_size == 0) {
-+ /* No extra arguments. Trivial to handle */
-+ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
-+ } else {
-+ char * extra;
-+ int err;
-+
-+ /* Check what user space is giving us */
-+ if(IW_IS_SET(cmd)) {
-+ /* Check NULL pointer */
-+ if((iwr->u.data.pointer == NULL) &&
-+ (iwr->u.data.length != 0))
-+ return -EFAULT;
-+
-+ /* Does it fits within bounds ? */
-+ if(iwr->u.data.length > (descr->set_args &
-+ IW_PRIV_SIZE_MASK))
-+ return -E2BIG;
-+ } else {
-+ /* Check NULL pointer */
-+ if(iwr->u.data.pointer == NULL)
-+ return -EFAULT;
-+ }
-+
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
-+#endif /* WE_IOCTL_DEBUG */
-+
-+ /* Always allocate for max space. Easier, and won't last
-+ * long... */
-+ extra = kmalloc(extra_size, GFP_KERNEL);
-+ if (extra == NULL) {
-+ return -ENOMEM;
-+ }
-+
-+ /* If it is a SET, get all the extra data in here */
-+ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-+ err = copy_from_user(extra, iwr->u.data.pointer,
-+ extra_size);
-+ if (err) {
-+ kfree(extra);
-+ return -EFAULT;
-+ }
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
-+#endif /* WE_IOCTL_DEBUG */
-+ }
-+
-+ /* Call the handler */
-+ ret = handler(dev, &info, &(iwr->u), extra);
-+
-+ /* If we have something to return to the user */
-+ if (!ret && IW_IS_GET(cmd)) {
-+ err = copy_to_user(iwr->u.data.pointer, extra,
-+ extra_size);
-+ if (err)
-+ ret = -EFAULT;
-+#ifdef WE_IOCTL_DEBUG
-+ printk(KERN_DEBUG "Wrote %d elem\n",
-+ iwr->u.data.length);
-+#endif /* WE_IOCTL_DEBUG */
-+ }
-+
-+ /* Cleanup - I told you it wasn't that long ;-) */
-+ kfree(extra);
-+ }
-+
-+
-+ /* Call commit handler if needed and defined */
-+ if(ret == -EIWCOMMIT)
-+ ret = call_commit_handler(dev);
-+
-+ return ret;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Main IOCTl dispatcher. Called from the main networking code
-+ * (dev_ioctl() in net/core/dev.c).
-+ * Check the type of IOCTL and call the appropriate wrapper...
-+ */
-+int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
-+{
-+ struct net_device *dev;
-+ iw_handler handler;
-+
-+ /* Permissions are already checked in dev_ioctl() before calling us.
-+ * The copy_to/from_user() of ifr is also dealt with in there */
-+
-+ /* Make sure the device exist */
-+ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
-+ return -ENODEV;
-+
-+ /* A bunch of special cases, then the generic case...
-+ * Note that 'cmd' is already filtered in dev_ioctl() with
-+ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
-+ switch(cmd)
-+ {
-+ case SIOCGIWSTATS:
-+ /* Get Wireless Stats */
-+ return dev_iwstats(dev, ifr);
-+
-+ case SIOCGIWPRIV:
-+ /* Check if we have some wireless handlers defined */
-+ if(dev->wireless_handlers != NULL) {
-+ /* We export to user space the definition of
-+ * the private handler ourselves */
-+ return ioctl_export_private(dev, ifr);
-+ }
-+ // ## Fall-through for old API ##
-+ default:
-+ /* Generic IOCTL */
-+ /* Basic check */
-+ if (!netif_device_present(dev))
-+ return -ENODEV;
-+ /* New driver API : try to find the handler */
-+ handler = get_handler(dev, cmd);
-+ if(handler != NULL) {
-+ /* Standard and private are not the same */
-+ if(cmd < SIOCIWFIRSTPRIV)
-+ return ioctl_standard_call(dev,
-+ ifr,
-+ cmd,
-+ handler);
-+ else
-+ return ioctl_private_call(dev,
-+ ifr,
-+ cmd,
-+ handler);
-+ }
-+ /* Old driver API : call driver ioctl handler */
-+ if (dev->do_ioctl) {
-+ return dev->do_ioctl(dev, ifr, cmd);
-+ }
-+ return -EOPNOTSUPP;
-+ }
-+ /* Not reached */
-+ return -EINVAL;
-+}
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff
deleted file mode 100644
index 539b160068..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff
+++ /dev/null
@@ -1,838 +0,0 @@
-diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h
---- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002
-+++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002
-@@ -440,12 +440,14 @@ enum
- #define IFLA_COST IFLA_COST
- IFLA_PRIORITY,
- #define IFLA_PRIORITY IFLA_PRIORITY
-- IFLA_MASTER
-+ IFLA_MASTER,
- #define IFLA_MASTER IFLA_MASTER
-+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
-+#define IFLA_WIRELESS IFLA_WIRELESS
- };
-
-
--#define IFLA_MAX IFLA_MASTER
-+#define IFLA_MAX IFLA_WIRELESS
-
- #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
- #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
-diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h
---- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002
-+++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002
-@@ -1,10 +1,10 @@
- /*
- * This file define a set of standard wireless extensions
- *
-- * Version : 13 6.12.01
-+ * Version : 14 25.1.02
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
-+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
- */
-
- #ifndef _LINUX_WIRELESS_H
-@@ -40,7 +40,7 @@
- * # include/linux/netdevice.h (one place)
- * # include/linux/proc_fs.h (one place)
- *
-- * New driver API (2001 -> onward) :
-+ * New driver API (2002 -> onward) :
- * -------------------------------
- * This file is only concerned with the user space API and common definitions.
- * The new driver API is defined and documented in :
-@@ -49,6 +49,11 @@
- * Note as well that /proc/net/wireless implementation has now moved in :
- * # include/linux/wireless.c
- *
-+ * Wireless Events (2002 -> onward) :
-+ * --------------------------------
-+ * Events are defined at the end of this file, and implemented in :
-+ * # include/linux/wireless.c
-+ *
- * Other comments :
- * --------------
- * Do not add here things that are redundant with other mechanisms
-@@ -75,7 +80,7 @@
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
--#define WIRELESS_EXT 13
-+#define WIRELESS_EXT 14
-
- /*
- * Changes :
-@@ -141,6 +146,13 @@
- * - Document creation of new driver API.
- * - Extract union iwreq_data from struct iwreq (for new driver API).
- * - Rename SIOCSIWNAME as SIOCSIWCOMMIT
-+ *
-+ * V13 to V14
-+ * ----------
-+ * - Wireless Events support : define struct iw_event
-+ * - Define additional specific event numbers
-+ * - Add "addr" and "param" fields in union iwreq_data
-+ * - AP scanning stuff (SIOCSIWSCAN and friends)
- */
-
- /**************************** CONSTANTS ****************************/
-@@ -175,6 +187,8 @@
- #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
- #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */
- #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */
-+#define SIOCSIWSCAN 0x8B18 /* trigger scanning */
-+#define SIOCGIWSCAN 0x8B19 /* get scanning results */
-
- /* 802.11 specific support */
- #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */
-@@ -238,6 +252,15 @@
- #define IW_IS_SET(cmd) (!((cmd) & 0x1))
- #define IW_IS_GET(cmd) ((cmd) & 0x1)
-
-+/* ----------------------- WIRELESS EVENTS ----------------------- */
-+/* Those are *NOT* ioctls, do not issue request on them !!! */
-+/* Most events use the same identifier as ioctl requests */
-+
-+#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */
-+#define IWEVQUAL 0x8C01 /* Quality part of statistics */
-+
-+#define IWEVFIRST 0x8C00
-+
- /* ------------------------- PRIVATE INFO ------------------------- */
- /*
- * The following is used with SIOCGIWPRIV. It allow a driver to define
-@@ -340,6 +363,19 @@
- #define IW_RETRY_MAX 0x0002 /* Value is a maximum */
- #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
-
-+/* Scanning request flags */
-+#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */
-+#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */
-+#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */
-+#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */
-+#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */
-+#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */
-+#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */
-+#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */
-+#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */
-+/* Maximum size of returned data */
-+#define IW_SCAN_MAX_DATA 4096 /* In bytes */
-+
- /****************************** TYPES ******************************/
-
- /* --------------------------- SUBTYPES --------------------------- */
-@@ -466,9 +502,12 @@ union iwreq_data
-
- struct iw_point encoding; /* Encoding stuff : tokens */
- struct iw_param power; /* PM duration/timeout */
-+ struct iw_quality qual; /* Quality part of statistics */
-
- struct sockaddr ap_addr; /* Access point address */
-+ struct sockaddr addr; /* Destination address (hw) */
-
-+ struct iw_param param; /* Other small parameters */
- struct iw_point data; /* Other large parameters */
- };
-
-@@ -595,5 +634,36 @@ struct iw_priv_args
- __u16 get_args; /* Type and number of args */
- char name[IFNAMSIZ]; /* Name of the extension */
- };
-+
-+/* ----------------------- WIRELESS EVENTS ----------------------- */
-+/*
-+ * Wireless events are carried through the rtnetlink socket to user
-+ * space. They are encapsulated in the IFLA_WIRELESS field of
-+ * a RTM_NEWLINK message.
-+ */
-+
-+/*
-+ * A Wireless Event. Contains basically the same data as the ioctl...
-+ */
-+struct iw_event
-+{
-+ __u16 len; /* Real lenght of this stuff */
-+ __u16 cmd; /* Wireless IOCTL */
-+ union iwreq_data u; /* IOCTL fixed payload */
-+};
-+
-+/* Size of the Event prefix (including padding and alignement junk) */
-+#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data))
-+/* Size of the various events */
-+#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
-+#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
-+#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
-+#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point))
-+#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param))
-+#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
-+#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
-+
-+/* Note : in the case of iw_point, the extra data will come at the
-+ * end of the event */
-
- #endif /* _LINUX_WIRELESS_H */
-diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h
---- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002
-+++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002
-@@ -1,10 +1,10 @@
- /*
- * This file define the new driver API for Wireless Extensions
- *
-- * Version : 2 6.12.01
-+ * Version : 3 17.1.02
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
-+ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
- */
-
- #ifndef _IW_HANDLER_H
-@@ -33,7 +33,7 @@
- * o The user space interface is tied to ioctl because of the use
- * copy_to/from_user.
- *
-- * New driver API (2001 -> onward) :
-+ * New driver API (2002 -> onward) :
- * -------------------------------
- * The new driver API is just a bunch of standard functions (handlers),
- * each handling a specific Wireless Extension. The driver just export
-@@ -206,7 +206,18 @@
- * will be needed...
- * I just plan to increment with each new version.
- */
--#define IW_HANDLER_VERSION 2
-+#define IW_HANDLER_VERSION 3
-+
-+/*
-+ * Changes :
-+ *
-+ * V2 to V3
-+ * --------
-+ * - Move event definition in <linux/wireless.h>
-+ * - Add Wireless Event support :
-+ * o wireless_send_event() prototype
-+ * o iwe_stream_add_event/point() inline functions
-+ */
-
- /**************************** CONSTANTS ****************************/
-
-@@ -225,6 +236,7 @@
- #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */
- #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */
- #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */
-+#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */
-
- /* Handling flags */
- /* Most are not implemented. I just use them as a reminder of some
-@@ -233,7 +245,8 @@
- /* Wrapper level flags */
- #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
- #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
--#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */
-+#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
-+ /* SET : Omit payload from generated iwevent */
- /* Driver level flags */
- #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
-
-@@ -303,25 +316,6 @@ struct iw_handler_def
- * 'struct net_device' to here, to minimise bloat. */
- };
-
--/* ----------------------- WIRELESS EVENTS ----------------------- */
--/*
-- * Currently we don't support events, so let's just plan for the
-- * future...
-- */
--
--/*
-- * A Wireless Event.
-- */
--// How do we define short header ? We don't want a flag on length.
--// Probably a flag on event ? Highest bit to zero...
--struct iw_event
--{
-- __u16 length; /* Lenght of this stuff */
-- __u16 event; /* Wireless IOCTL */
-- union iwreq_data header; /* IOCTL fixed payload */
-- char extra[0]; /* Optional IOCTL data */
--};
--
- /* ---------------------- IOCTL DESCRIPTION ---------------------- */
- /*
- * One of the main goal of the new interface is to deal entirely with
-@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char *
- extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
-
- /* Second : functions that may be called by driver modules */
--/* None yet */
-
--#endif /* _LINUX_WIRELESS_H */
-+/* Send a single event to user space */
-+extern void wireless_send_event(struct net_device * dev,
-+ unsigned int cmd,
-+ union iwreq_data * wrqu,
-+ char * extra);
-+
-+/* We may need a function to send a stream of events to user space.
-+ * More on that later... */
-+
-+/************************* INLINE FUNTIONS *************************/
-+/*
-+ * Function that are so simple that it's more efficient inlining them
-+ */
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Wrapper to add an Wireless Event to a stream of events.
-+ */
-+static inline char *
-+iwe_stream_add_event(char * stream, /* Stream of events */
-+ char * ends, /* End of stream */
-+ struct iw_event *iwe, /* Payload */
-+ int event_len) /* Real size of payload */
-+{
-+ /* Check if it's possible */
-+ if((stream + event_len) < ends) {
-+ iwe->len = event_len;
-+ memcpy(stream, (char *) iwe, event_len);
-+ stream += event_len;
-+ }
-+ return stream;
-+}
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Wrapper to add an short Wireless Event containing a pointer to a
-+ * stream of events.
-+ */
-+static inline char *
-+iwe_stream_add_point(char * stream, /* Stream of events */
-+ char * ends, /* End of stream */
-+ struct iw_event *iwe, /* Payload */
-+ char * extra)
-+{
-+ int event_len = IW_EV_POINT_LEN + iwe->u.data.length;
-+ /* Check if it's possible */
-+ if((stream + event_len) < ends) {
-+ iwe->len = event_len;
-+ memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
-+ memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
-+ stream += event_len;
-+ }
-+ return stream;
-+}
-+
-+/*------------------------------------------------------------------*/
-+/*
-+ * Wrapper to add a value to a Wireless Event in a stream of events.
-+ * Be careful, this one is tricky to use properly :
-+ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
-+ */
-+static inline char *
-+iwe_stream_add_value(char * event, /* Event in the stream */
-+ char * value, /* Value in event */
-+ char * ends, /* End of stream */
-+ struct iw_event *iwe, /* Payload */
-+ int event_len) /* Real size of payload */
-+{
-+ /* Don't duplicate LCP */
-+ event_len -= IW_EV_LCP_LEN;
-+
-+ /* Check if it's possible */
-+ if((value + event_len) < ends) {
-+ /* Add new value */
-+ memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
-+ value += event_len;
-+ /* Patch LCP */
-+ iwe->len = value - event;
-+ memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
-+ }
-+ return value;
-+}
-+
-+#endif /* _IW_HANDLER_H */
-diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c
---- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002
-+++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002
-@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf);
- EXPORT_SYMBOL(net_call_rx_atomic);
- EXPORT_SYMBOL(softnet_data);
-
-+#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
-+/* Don't include the whole header mess for a single function */
-+extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
-+EXPORT_SYMBOL(wireless_send_event);
-+#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
-+
- #endif /* CONFIG_NET */
-diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c
---- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002
-+++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002
-@@ -2,7 +2,7 @@
- * This file implement the Wireless Extensions APIs.
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
-- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
-+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
- *
- * (As all part of the Linux kernel, this file is GPL)
- */
-@@ -25,6 +25,16 @@
- * o Added iw_handler handling ;-)
- * o Added standard ioctl description
- * o Initial dumb commit strategy based on orinoco.c
-+ *
-+ * v3 - 19.12.01 - Jean II
-+ * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
-+ * o Add event dispatcher function
-+ * o Add event description
-+ * o Propagate events as rtnetlink IFLA_WIRELESS option
-+ * o Generate event on selected SET requests
-+ *
-+ * v4 - 18.04.01 - Jean II
-+ * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
- */
-
- /***************************** INCLUDES *****************************/
-@@ -33,6 +43,7 @@
- #include <linux/config.h> /* Not needed ??? */
- #include <linux/types.h> /* off_t */
- #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
-+#include <linux/rtnetlink.h> /* rtnetlink stuff */
-
- #include <linux/wireless.h> /* Pretty obvious */
- #include <net/iw_handler.h> /* New driver API */
-@@ -44,14 +55,23 @@
-
- /* Debuging stuff */
- #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
-+#undef WE_EVENT_DEBUG /* Debug Event dispatcher */
-+
-+/* Options */
-+#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
-+#define WE_SET_EVENT /* Generate an event on some set commands */
-
- /************************* GLOBAL VARIABLES *************************/
- /*
- * You should not use global variables, because or re-entrancy.
- * On our case, it's only const, so it's OK...
- */
-+/*
-+ * Meta-data about all the standard Wireless Extension request we
-+ * know about.
-+ */
- static const struct iw_ioctl_description standard_ioctl[] = {
-- /* SIOCSIWCOMMIT (internal) */
-+ /* SIOCSIWCOMMIT */
- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
- /* SIOCGIWNAME */
- { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
-@@ -99,18 +119,18 @@ static const struct iw_ioctl_description
- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
- /* SIOCGIWAPLIST */
- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
-- /* -- hole -- */
-- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-- /* -- hole -- */
-- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-+ /* SIOCSIWSCAN */
-+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
-+ /* SIOCGIWSCAN */
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
- /* SIOCSIWESSID */
-- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
- /* SIOCGIWESSID */
-- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
- /* SIOCSIWNICKN */
-- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
- /* SIOCGIWNICKN */
-- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
- /* -- hole -- */
- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
- /* -- hole -- */
-@@ -136,7 +156,7 @@ static const struct iw_ioctl_description
- /* SIOCGIWRETRY */
- { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
- /* SIOCSIWENCODE */
-- { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
-+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
- /* SIOCGIWENCODE */
- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
- /* SIOCSIWPOWER */
-@@ -144,9 +164,38 @@ static const struct iw_ioctl_description
- /* SIOCGIWPOWER */
- { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
- };
-+static const int standard_ioctl_num = (sizeof(standard_ioctl) /
-+ sizeof(struct iw_ioctl_description));
-+
-+/*
-+ * Meta-data about all the additional standard Wireless Extension events
-+ * we know about.
-+ */
-+static const struct iw_ioctl_description standard_event[] = {
-+ /* IWEVTXDROP */
-+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
-+ /* IWEVQUAL */
-+ { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
-+};
-+static const int standard_event_num = (sizeof(standard_event) /
-+ sizeof(struct iw_ioctl_description));
-
- /* Size (in bytes) of the various private data types */
--char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
-+static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
-+
-+/* Size (in bytes) of various events */
-+static const int event_type_size[] = {
-+ IW_EV_LCP_LEN,
-+ 0,
-+ IW_EV_CHAR_LEN,
-+ 0,
-+ IW_EV_UINT_LEN,
-+ IW_EV_FREQ_LEN,
-+ IW_EV_POINT_LEN, /* Without variable payload */
-+ IW_EV_PARAM_LEN,
-+ IW_EV_ADDR_LEN,
-+ IW_EV_QUAL_LEN,
-+};
-
- /************************ COMMON SUBROUTINES ************************/
- /*
-@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4,
- static inline iw_handler get_handler(struct net_device *dev,
- unsigned int cmd)
- {
-- unsigned int index; /* MUST be unsigned */
-+ /* Don't "optimise" the following variable, it will crash */
-+ unsigned int index; /* *MUST* be unsigned */
-
- /* Check if we have some wireless handlers defined */
- if(dev->wireless_handlers == NULL)
-@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats
- stats->status,
- stats->qual.qual,
- stats->qual.updated & 1 ? '.' : ' ',
-- stats->qual.level,
-+ ((__u8) stats->qual.level),
- stats->qual.updated & 2 ? '.' : ' ',
-- stats->qual.noise,
-+ ((__u8) stats->qual.noise),
- stats->qual.updated & 4 ? '.' : ' ',
- stats->discard.nwid,
- stats->discard.code,
-@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st
- int ret = -EINVAL;
-
- /* Get the description of the IOCTL */
-+ if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
-+ return -EOPNOTSUPP;
- descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
-+ printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
- ifr->ifr_name, cmd);
-- printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-+ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
- #endif /* WE_IOCTL_DEBUG */
-
- /* Prepare the call */
-@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st
-
- /* Check if we have a pointer to user space data or not */
- if(descr->header_type != IW_HEADER_TYPE_POINT) {
-+
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, &info, &(iwr->u), NULL);
-+
-+#ifdef WE_SET_EVENT
-+ /* Generate an event to notify listeners of the change */
-+ if((descr->flags & IW_DESCR_FLAG_EVENT) &&
-+ ((ret == 0) || (ret == -EIWCOMMIT)))
-+ wireless_send_event(dev, cmd, &(iwr->u), NULL);
-+#endif /* WE_SET_EVENT */
- } else {
- char * extra;
- int err;
-@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st
- }
-
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "Malloc %d bytes\n",
-- descr->max_tokens * descr->token_size);
-+ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-+ dev->name, descr->max_tokens * descr->token_size);
- #endif /* WE_IOCTL_DEBUG */
-
- /* Always allocate for max space. Easier, and won't last
-@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st
- return -EFAULT;
- }
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "Got %d bytes\n",
-+ printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
-+ dev->name,
- iwr->u.data.length * descr->token_size);
- #endif /* WE_IOCTL_DEBUG */
- }
-@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st
- if (err)
- ret = -EFAULT;
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "Wrote %d bytes\n",
-+ printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
-+ dev->name,
- iwr->u.data.length * descr->token_size);
- #endif /* WE_IOCTL_DEBUG */
- }
-
-+#ifdef WE_SET_EVENT
-+ /* Generate an event to notify listeners of the change */
-+ if((descr->flags & IW_DESCR_FLAG_EVENT) &&
-+ ((ret == 0) || (ret == -EIWCOMMIT))) {
-+ if(descr->flags & IW_DESCR_FLAG_RESTRICT)
-+ /* If the event is restricted, don't
-+ * export the payload */
-+ wireless_send_event(dev, cmd, &(iwr->u), NULL);
-+ else
-+ wireless_send_event(dev, cmd, &(iwr->u),
-+ extra);
-+ }
-+#endif /* WE_SET_EVENT */
-+
- /* Cleanup - I told you it wasn't that long ;-) */
- kfree(extra);
- }
-@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str
- }
-
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
-+ printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
- ifr->ifr_name, cmd);
- if(descr) {
-- printk(KERN_DEBUG "Name %s, set %X, get %X\n",
-- descr->name, descr->set_args, descr->get_args);
-+ printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
-+ dev->name, descr->name,
-+ descr->set_args, descr->get_args);
- }
- #endif /* WE_IOCTL_DEBUG */
-
-@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str
- }
-
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
-+ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-+ dev->name, extra_size);
- #endif /* WE_IOCTL_DEBUG */
-
- /* Always allocate for max space. Easier, and won't last
-@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str
- return -EFAULT;
- }
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
-+ printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
-+ dev->name, iwr->u.data.length);
- #endif /* WE_IOCTL_DEBUG */
- }
-
-@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str
- if (err)
- ret = -EFAULT;
- #ifdef WE_IOCTL_DEBUG
-- printk(KERN_DEBUG "Wrote %d elem\n",
-- iwr->u.data.length);
-+ printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
-+ dev->name, iwr->u.data.length);
- #endif /* WE_IOCTL_DEBUG */
- }
-
-@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq
- }
- /* Not reached */
- return -EINVAL;
-+}
-+
-+/************************* EVENT PROCESSING *************************/
-+/*
-+ * Process events generated by the wireless layer or the driver.
-+ * Most often, the event will be propagated through rtnetlink
-+ */
-+
-+#ifdef WE_EVENT_NETLINK
-+/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
-+ * It is declared in <linux/rtnetlink.h> */
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Fill a rtnetlink message with our event data.
-+ * Note that we propage only the specified event and don't dump the
-+ * current wireless config. Dumping the wireless config is far too
-+ * expensive (for each parameter, the driver need to query the hardware).
-+ */
-+static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
-+ struct net_device * dev,
-+ int type,
-+ char * event,
-+ int event_len)
-+{
-+ struct ifinfomsg *r;
-+ struct nlmsghdr *nlh;
-+ unsigned char *b = skb->tail;
-+
-+ nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
-+ r = NLMSG_DATA(nlh);
-+ r->ifi_family = AF_UNSPEC;
-+ r->ifi_type = dev->type;
-+ r->ifi_index = dev->ifindex;
-+ r->ifi_flags = dev->flags;
-+ r->ifi_change = 0; /* Wireless changes don't affect those flags */
-+
-+ /* Add the wireless events in the netlink packet */
-+ RTA_PUT(skb, IFLA_WIRELESS,
-+ event_len, event);
-+
-+ nlh->nlmsg_len = skb->tail - b;
-+ return skb->len;
-+
-+nlmsg_failure:
-+rtattr_failure:
-+ skb_trim(skb, b - skb->data);
-+ return -1;
-+}
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Create and broadcast and send it on the standard rtnetlink socket
-+ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
-+ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
-+ * within a RTM_NEWLINK event.
-+ */
-+static inline void rtmsg_iwinfo(struct net_device * dev,
-+ char * event,
-+ int event_len)
-+{
-+ struct sk_buff *skb;
-+ int size = NLMSG_GOODSIZE;
-+
-+ skb = alloc_skb(size, GFP_ATOMIC);
-+ if (!skb)
-+ return;
-+
-+ if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
-+ event, event_len) < 0) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+ NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
-+ netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
-+}
-+#endif /* WE_EVENT_NETLINK */
-+
-+/* ---------------------------------------------------------------- */
-+/*
-+ * Main event dispatcher. Called from other parts and drivers.
-+ * Send the event on the apropriate channels.
-+ * May be called from interrupt context.
-+ */
-+void wireless_send_event(struct net_device * dev,
-+ unsigned int cmd,
-+ union iwreq_data * wrqu,
-+ char * extra)
-+{
-+ const struct iw_ioctl_description * descr = NULL;
-+ int extra_len = 0;
-+ struct iw_event *event; /* Mallocated whole event */
-+ int event_len; /* Its size */
-+ int hdr_len; /* Size of the event header */
-+ /* Don't "optimise" the following variable, it will crash */
-+ unsigned cmd_index; /* *MUST* be unsigned */
-+
-+ /* Get the description of the IOCTL */
-+ if(cmd <= SIOCIWLAST) {
-+ cmd_index = cmd - SIOCIWFIRST;
-+ if(cmd_index < standard_ioctl_num)
-+ descr = &(standard_ioctl[cmd_index]);
-+ } else {
-+ cmd_index = cmd - IWEVFIRST;
-+ if(cmd_index < standard_event_num)
-+ descr = &(standard_event[cmd_index]);
-+ }
-+ /* Don't accept unknown events */
-+ if(descr == NULL) {
-+ /* Note : we don't return an error to the driver, because
-+ * the driver would not know what to do about it. It can't
-+ * return an error to the user, because the event is not
-+ * initiated by a user request.
-+ * The best the driver could do is to log an error message.
-+ * We will do it ourselves instead...
-+ */
-+ printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
-+ dev->name, cmd);
-+ return;
-+ }
-+#ifdef WE_EVENT_DEBUG
-+ printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
-+ dev->name, cmd);
-+ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-+#endif /* WE_EVENT_DEBUG */
-+
-+ /* Check extra parameters and set extra_len */
-+ if(descr->header_type == IW_HEADER_TYPE_POINT) {
-+ /* Check if number of token fits within bounds */
-+ if(wrqu->data.length > descr->max_tokens) {
-+ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
-+ return;
-+ }
-+ if(wrqu->data.length < descr->min_tokens) {
-+ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
-+ return;
-+ }
-+ /* Calculate extra_len - extra is NULL for restricted events */
-+ if(extra != NULL)
-+ extra_len = wrqu->data.length * descr->token_size;
-+#ifdef WE_EVENT_DEBUG
-+ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
-+#endif /* WE_EVENT_DEBUG */
-+ }
-+
-+ /* Total length of the event */
-+ hdr_len = event_type_size[descr->header_type];
-+ event_len = hdr_len + extra_len;
-+
-+#ifdef WE_EVENT_DEBUG
-+ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
-+#endif /* WE_EVENT_DEBUG */
-+
-+ /* Create temporary buffer to hold the event */
-+ event = kmalloc(event_len, GFP_ATOMIC);
-+ if(event == NULL)
-+ return;
-+
-+ /* Fill event */
-+ event->len = event_len;
-+ event->cmd = cmd;
-+ memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
-+ if(extra != NULL)
-+ memcpy(((char *) event) + hdr_len, extra, extra_len);
-+
-+#ifdef WE_EVENT_NETLINK
-+ /* rtnetlink event channel */
-+ rtmsg_iwinfo(dev, (char *) event, event_len);
-+#endif /* WE_EVENT_NETLINK */
-+
-+ /* Cleanup */
-+ kfree(event);
-+
-+ return; /* Always success, I guess ;-) */
- }
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch
deleted file mode 100644
index a7eefd1e16..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#
-# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
-#
-
---- linux/drivers/char/collie_keymap.map~keymap-more-sane 2003-05-13 11:18:18.000000000 +0200
-+++ linux/drivers/char/collie_keymap.map 2004-06-23 00:03:19.000000000 +0200
-@@ -55,9 +55,11 @@
- # (Cancel:34) F9 -> Escape
- keycode 34 = Escape
- keycode 35 = Left
-+ control keycode 35 = Decr_Console
- keycode 36 = Up
- keycode 37 = Down
- keycode 38 = Right
-+ control keycode 38 = Incr_Console
- # (OK:39) F4 -> Return
- keycode 39 = Return
- keycode 40 =
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch
deleted file mode 100644
index c006684f23..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch
+++ /dev/null
@@ -1,2598 +0,0 @@
---- linux/drivers/video/fbcon.c 2003-02-27 21:47:36.000000000 -0600
-+++ linux.new/drivers/video/fbcon.c 2003-02-27 18:39:39.000000000 -0600
-@@ -126,8 +126,8 @@
- #define LOGO_H (320-16)
- #define LOGO_W 240
- #else
--#define LOGO_H 80
--#define LOGO_W 80
-+#define LOGO_H 52
-+#define LOGO_W 240
- #endif
- #define LOGO_LINE (LOGO_W/8)
- #if defined(CONFIG_SHARP_LOGO_SCREEN)
---- linux/include/linux/linux_logo.h 2001-06-11 21:15:27.000000000 -0500
-+++ linux.new/include/linux/linux_logo.h 2003-02-27 15:58:15.000000000 -0600
-@@ -1,4 +1,4 @@
--/* $Id$
-+/* linux_logo.h created with fblogo, 2002/12/29 02:43:36
- * include/linux/linux_logo.h: This is a linux logo
- * to be displayed on boot.
- *
-@@ -7,907 +7,1673 @@
- *
- * You can put anything here, but:
- * LINUX_LOGO_COLORS has to be less than 224
-- * image size has to be 80x80
-- * values have to start from 0x20
-- * (i.e. RGB(linux_logo_red[0],
-- * linux_logo_green[0],
-- * linux_logo_blue[0]) is color 0x20)
-- * BW image has to be 80x80 as well, with MS bit
-- * on the left
-- * Serial_console ascii image can be any size,
-- * but should contain %s to display the version
-+ * Generated by fblogo version 0.5.0
-+ *
-+ *
-+ * Remember to modify drivers/video/fbcon.c:
-+ * Change "#define LOGO_H 80" to "#define LOGO_H 52"
-+ * Change "#define LOGO_W 80" to "#define LOGO_W 240"
- */
-
- #ifndef __HAVE_ARCH_LINUX_LOGO
--#define LINUX_LOGO_COLORS 187
-+#define LINUX_LOGO_COLORS 223
- #endif
--
- #ifdef INCLUDE_LINUX_LOGO_DATA
--
- #ifndef __HAVE_ARCH_LINUX_LOGO
--
- unsigned char linux_logo_red[] __initdata = {
-- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
-- 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
-- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
-- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
-- 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
-- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
-- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
-- 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
-- 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
-- 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
-- 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
-- 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
-- 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
-- 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
-- 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
-- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x12,
-- 0x4a, 0x8e, 0xf2, 0xf6, 0xf6, 0xee, 0xb5, 0xe4,
-- 0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16,
-- 0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
-- 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae,
-- 0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf,
-- 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82,
-- 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52,
-- 0x59, 0x64, 0x5e,
-+ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA,
-+ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE,
-+ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA,
-+ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36,
-+ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82,
-+ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6,
-+ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E,
-+ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x32, 0x7E,
-+ 0x3A, 0x16, 0x02, 0x02, 0x06, 0x1F, 0x02, 0x02,
-+ 0x06, 0x02, 0x22, 0x3A, 0x35, 0x16, 0x0A, 0x02,
-+ 0x2A, 0x3E, 0x39, 0x32, 0x2A, 0x1E, 0x16, 0x06,
-+ 0x22, 0x22, 0x1E, 0x16, 0x6E, 0x82, 0x6E, 0x2E,
-+ 0x1E, 0x2E, 0x1E, 0x0A, 0x3A, 0xDA, 0xFE, 0xFA,
-+ 0xFA, 0xE2, 0x6A, 0x3A, 0x1A, 0xFA, 0xF6, 0x9E,
-+ 0x02, 0x6E, 0xFE, 0xF6, 0x3E, 0x66, 0x52, 0x1B,
-+ 0xD6, 0x5A, 0xEE, 0xC6, 0x72, 0x36, 0x22, 0x1E,
-+ 0x02, 0x96, 0xF6, 0xDE, 0xA2, 0xD6, 0x39, 0x0E,
-+ 0xAA, 0x52, 0x5A, 0xD2, 0xDE, 0x61, 0x46, 0xDE,
-+ 0x7A, 0x57, 0x9E, 0xBA, 0xB6, 0x4A, 0x5A, 0xA6,
-+ 0x96, 0x23, 0x1E, 0x12, 0x9A, 0x4E, 0x76, 0xAE,
-+ 0x2E, 0xBE, 0x86, 0x48, 0xA6, 0x52, 0x06, 0x2E,
-+ 0x56, 0x13, 0x2A, 0x4A, 0x36, 0x56, 0x2E, 0x1E,
-+ 0x46, 0x3A, 0x66, 0x02, 0x3D, 0x3E, 0x2E, 0x3E,
-+ 0x4A, 0x32, 0x52, 0x72, 0x76, 0x67, 0x68, 0x5A,
-+ 0x3A, 0x1A, 0x0E, 0x2E, 0x4E, 0x02, 0x3E, 0x0A,
-+ 0x28, 0x42, 0x10, 0x26, 0x8E, 0x0A, 0x86, 0xC2,
-+ 0x02, 0x6E, 0x92, 0x02, 0x42, 0x02, 0xBE, 0x4E,
-+ 0x02, 0x22, 0x02, 0x3E, 0x3A, 0x32
- };
-
- unsigned char linux_logo_green[] __initdata = {
-- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
-- 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
-- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
-- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
-- 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
-- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
-- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
-- 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
-- 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
-- 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
-- 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
-- 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
-- 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
-- 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
-- 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
-- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x0e,
-- 0x36, 0x86, 0xba, 0xbe, 0xe6, 0xcc, 0x8e, 0xb8,
-- 0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12,
-- 0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
-- 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87,
-- 0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76,
-- 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62,
-- 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e,
-- 0x51, 0x52, 0x56,
-+ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA,
-+ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE,
-+ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA,
-+ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36,
-+ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82,
-+ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6,
-+ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E,
-+ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x2E, 0x7E,
-+ 0x3A, 0x3E, 0x6A, 0xA2, 0x92, 0x30, 0x95, 0x76,
-+ 0x4E, 0x86, 0x36, 0x7E, 0x9A, 0x6E, 0x42, 0x56,
-+ 0x5A, 0xC2, 0xBE, 0xB2, 0xAA, 0x9A, 0x63, 0x1E,
-+ 0xA2, 0x9E, 0x96, 0x5A, 0x3A, 0x42, 0x4A, 0x52,
-+ 0x91, 0x46, 0x4E, 0x62, 0x22, 0x4A, 0x6E, 0x86,
-+ 0x92, 0x9A, 0x52, 0x4A, 0x76, 0x7A, 0x9E, 0x76,
-+ 0x62, 0x32, 0x5E, 0xAE, 0x3E, 0x66, 0x52, 0x81,
-+ 0xA6, 0x5A, 0xEE, 0xC6, 0x72, 0x5C, 0x6A, 0x8A,
-+ 0x36, 0x3E, 0xBA, 0xBA, 0xA2, 0xD6, 0xAA, 0x4E,
-+ 0x8A, 0x4E, 0x5A, 0xD2, 0xDE, 0x64, 0x32, 0x9A,
-+ 0x5E, 0x57, 0x9E, 0xBA, 0xB6, 0x52, 0x62, 0xA6,
-+ 0x9A, 0x47, 0x3E, 0x56, 0x02, 0x1A, 0x76, 0xAE,
-+ 0x4A, 0x02, 0x02, 0x38, 0x02, 0x4A, 0x46, 0x86,
-+ 0x1E, 0x2E, 0x7A, 0xD2, 0x5E, 0x26, 0x92, 0x62,
-+ 0xCA, 0x42, 0x66, 0x26, 0x67, 0xB6, 0x62, 0x92,
-+ 0x9E, 0x72, 0xB2, 0xF2, 0xFE, 0xDE, 0xFE, 0xFE,
-+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x8A, 0x2A,
-+ 0x42, 0x52, 0x6A, 0x26, 0x8E, 0x26, 0x86, 0xC2,
-+ 0xE2, 0x6E, 0x92, 0xBE, 0x42, 0xC6, 0xBE, 0x4E,
-+ 0xEE, 0x5A, 0xEA, 0x3E, 0x4A, 0x32
- };
-
- unsigned char linux_logo_blue[] __initdata = {
-- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
-- 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
-- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
-- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
-- 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
-- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
-- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
-- 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
-- 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
-- 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
-- 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
-- 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
-- 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
-- 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
-- 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
-- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x06,
-- 0x0e, 0x6a, 0x0e, 0x0e, 0xbe, 0x5b, 0x2c, 0x3e,
-- 0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06,
-- 0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
-- 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32,
-- 0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06,
-- 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e,
-- 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22,
-- 0x42, 0x34, 0x42,
-+ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA,
-+ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE,
-+ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA,
-+ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36,
-+ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82,
-+ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6,
-+ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E,
-+ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x1A, 0x06,
-+ 0x1A, 0x2A, 0x36, 0x52, 0x46, 0x23, 0x4D, 0x3E,
-+ 0x2A, 0x42, 0x2A, 0x5A, 0x69, 0x42, 0x26, 0x2E,
-+ 0x42, 0x7E, 0x7C, 0x72, 0x6A, 0x5E, 0x3B, 0x12,
-+ 0x62, 0x5E, 0x5A, 0x36, 0x26, 0x1E, 0x26, 0x42,
-+ 0x56, 0x3A, 0x36, 0x36, 0x1E, 0x2E, 0x2A, 0x22,
-+ 0x22, 0x1A, 0x16, 0x42, 0x46, 0x26, 0x1E, 0x12,
-+ 0x32, 0x2A, 0x2E, 0x16, 0x2A, 0x1A, 0x2E, 0x4E,
-+ 0x12, 0x22, 0x02, 0x02, 0x12, 0x4A, 0x46, 0x52,
-+ 0x1E, 0x1E, 0x16, 0x0E, 0x02, 0x02, 0x6F, 0x2E,
-+ 0x0E, 0x1A, 0x06, 0x02, 0x02, 0x04, 0x22, 0x16,
-+ 0x0E, 0x12, 0x02, 0x02, 0x02, 0x0A, 0x5A, 0x02,
-+ 0x02, 0x1B, 0x2E, 0x32, 0x02, 0x02, 0x02, 0x02,
-+ 0x16, 0x02, 0x02, 0x10, 0x02, 0x02, 0x26, 0x5A,
-+ 0x02, 0x1F, 0x52, 0x8E, 0x22, 0x02, 0x5E, 0x3E,
-+ 0x86, 0x0E, 0x16, 0x16, 0x52, 0x7A, 0x4A, 0x66,
-+ 0x72, 0x52, 0x82, 0xB2, 0xBA, 0xA4, 0xB2, 0xAA,
-+ 0x9E, 0x8E, 0x88, 0x96, 0xA6, 0x82, 0x62, 0x1A,
-+ 0x34, 0x4A, 0x31, 0x16, 0x02, 0x1A, 0x02, 0x02,
-+ 0x72, 0x02, 0x02, 0x5E, 0x1A, 0x62, 0x02, 0x0E,
-+ 0x76, 0x1E, 0x76, 0x1E, 0x0A, 0x02
- };
-
- unsigned char linux_logo[] __initdata = {
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
-- 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-- 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
-- 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
-- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
-- 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
-- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
-- 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
-- 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
-- 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
-- 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
-- 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
-- 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
-- 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
-- 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
-- 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
-- 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
-- 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
-- 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
-- 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
-- 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
-- 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
-- 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
-- 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
-- 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
-- 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
-- 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
-- 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
-- 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
-- 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
-- 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
-- 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
-- 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
-- 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
-- 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
-- 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
-- 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
-- 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
-- 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
-- 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
-- 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
-- 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
-- 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
-- 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
-- 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
-- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
-- 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
-- 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
-- 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
-- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
-- 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
-- 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
-- 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
-- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
-- 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
-- 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
-- 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
-- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
-- 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
-- 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
-- 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
-- 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
-- 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
-- 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
-- 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
-- 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
-- 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
-- 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
-- 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
-- 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
-- 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
-- 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
-- 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
-- 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
-- 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
-- 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
-- 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
-- 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
-- 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
-- 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
-- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
-- 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
-- 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
-- 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
-- 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
-- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
-- 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
-- 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
-- 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
-- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
-- 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
-- 0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
-- 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
-- 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
-- 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
-- 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
-- 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
-- 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
-- 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
-- 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
-- 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
-- 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
-- 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
-- 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
-- 0x36, 0x24, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
-- 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
-- 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
-- 0x36, 0x3a, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x9b, 0x52, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
-- 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
-- 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
-- 0x23, 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x47, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
-- 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
-- 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
-- 0x2e, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x99, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
-- 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
-- 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
-- 0x54, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
-- 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
-- 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
-- 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21,
-- 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
-- 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x52, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x21,
-- 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
-- 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x22,
-- 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
-- 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
-- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23,
-- 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
-- 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
-- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22,
-- 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
-- 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
-- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
-- 0x24, 0x27, 0x9f, 0x24, 0x25, 0x28, 0x21, 0x36,
-- 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
-- 0x39, 0x4d, 0xa0, 0x84, 0x81, 0x57, 0x21, 0x39,
-- 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28,
-- 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
-- 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
-- 0x2d, 0xa1, 0x7a, 0xa2, 0xa3, 0xa3, 0x7f, 0x22,
-- 0x51, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0xa4, 0xa5, 0xa5, 0xa6, 0x61,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
-- 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
-- 0x4d, 0x91, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0x5a,
-- 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0xa7, 0xa8, 0x69, 0x66, 0xa9,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
-- 0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
-- 0x60, 0x85, 0xab, 0xac, 0xa3, 0xa3, 0xa3, 0x82,
-- 0x86, 0x36, 0x32, 0x3f, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0xad, 0xa2, 0xa8, 0xae, 0xaf,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
-- 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90,
-- 0x8b, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0x5d, 0xb1, 0x36, 0x24, 0x53, 0x9b, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
-- 0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
-- 0x7b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80,
-- 0x9f, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b,
-- 0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa2, 0xa2, 0xac,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x4b,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63,
-- 0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64,
-- 0xa2, 0xa2, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30,
-- 0x44, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85,
-- 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa2, 0xa3,
-- 0xa3, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36,
-- 0x2d, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe,
-- 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa2, 0xc1, 0x37, 0x35, 0x26, 0x23,
-- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36,
-- 0x24, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b,
-- 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa2, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27,
-- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa8, 0x89, 0x9f, 0x36, 0x36,
-- 0x32, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa2, 0xac,
-- 0xa2, 0x64, 0x64, 0xa2, 0xa2, 0xac, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x5d, 0xc3, 0x2c,
-- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x57, 0x27, 0x4d,
-- 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x99, 0x34, 0x9f, 0xb9, 0x7a, 0x7b, 0xa2, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xc2,
-- 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
-- 0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa8, 0x5f, 0x92, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
-- 0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0xa2, 0xc0,
-- 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
-- 0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x89, 0x45,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
-- 0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0xbe, 0xc3,
-- 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
-- 0x33, 0xc4, 0x63, 0xbe, 0xa2, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x72, 0x81, 0xc5,
-- 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-- 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
-- 0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa2, 0xab, 0x8b, 0xb0, 0x2c,
-- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
-- 0x35, 0x96, 0x75, 0xab, 0xa2, 0xac, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0x81, 0xb9,
-- 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
-- 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30,
-- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
-- 0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa2, 0xa2,
-- 0xac, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7b, 0x7a, 0xc7,
-- 0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
-- 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x64, 0x64,
-- 0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28,
-- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
-- 0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b,
-- 0x76, 0x7b, 0x64, 0x64, 0xa2, 0xac, 0xa3, 0xa3,
-- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x76, 0x85, 0xb9,
-- 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa2, 0xa3,
-- 0xa3, 0xa3, 0xac, 0xa2, 0x64, 0x76, 0xbe, 0x8b,
-- 0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
-- 0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90,
-- 0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa2,
-- 0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc,
-- 0x79, 0x9f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-- 0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64,
-- 0xac, 0xa2, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96,
-- 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f,
-- 0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d,
-- 0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd,
-- 0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
-- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
-- 0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76,
-- 0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34,
-- 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
-- 0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74,
-- 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79,
-- 0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
-- 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
-- 0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e,
-- 0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a,
-- 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
-- 0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1,
-- 0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3,
-- 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
-- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
-- 0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7,
-- 0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28,
-- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
-- 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
-- 0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51,
-- 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
-- 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
-- 0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80,
-- 0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
-- 0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33,
-- 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8,
-- 0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
-- 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
-- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
-- 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
-- 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
-- 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x23, 0x33, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x23, 0x61, 0x62, 0x2B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x35, 0x61, 0x63, 0x64, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x65, 0x66, 0x66, 0x67, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B,
-+ 0x3B, 0x68, 0x64, 0x69, 0x62, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x22, 0x23, 0x23, 0x55, 0x6A, 0x6B,
-+ 0x6C, 0x6D, 0x6E, 0x6F, 0x6F, 0x33, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
-+ 0x22, 0x23, 0x35, 0x33, 0x3B, 0x70, 0x71, 0x72,
-+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x23, 0x23, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x55,
-+ 0x2B, 0x34, 0x34, 0x42, 0x70, 0x71, 0x73, 0x78,
-+ 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x34, 0x22, 0x21,
-+ 0x55, 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x22, 0x3B, 0x7C, 0x7D, 0x7E, 0x34, 0x35,
-+ 0x21, 0x21, 0x21, 0x21, 0x35, 0x3B, 0x4C, 0x3C,
-+ 0x42, 0x3F, 0x56, 0x7F, 0x71, 0x74, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x79, 0x80, 0x81, 0x3C, 0x82,
-+ 0x83, 0x62, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x23, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
-+ 0x3B, 0x21, 0x55, 0x55, 0x2B, 0x34, 0x39, 0x3F,
-+ 0x2A, 0x57, 0x8B, 0x72, 0x74, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x75, 0x8C, 0x6F, 0x63,
-+ 0x63, 0x66, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x84, 0x85, 0x86, 0x8D, 0x88, 0x8E, 0x8F, 0x5E,
-+ 0x3C, 0x34, 0x3B, 0x34, 0x3F, 0x2A, 0x58, 0x57,
-+ 0x52, 0x46, 0x6C, 0x73, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x6E, 0x69,
-+ 0x69, 0x90, 0x34, 0x33, 0x22, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
-+ 0x91, 0x92, 0x8D, 0x87, 0x8E, 0x93, 0x8A, 0x35,
-+ 0x94, 0x95, 0x96, 0x56, 0x32, 0x32, 0x52, 0x5C,
-+ 0x4D, 0x82, 0x72, 0x78, 0x78, 0x78, 0x78, 0x79,
-+ 0x97, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, 0x6F,
-+ 0x62, 0x65, 0x34, 0x4C, 0x33, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
-+ 0x91, 0x86, 0x87, 0x88, 0x93, 0x98, 0x60, 0x3F,
-+ 0x99, 0x9A, 0x9A, 0x9B, 0x9C, 0x57, 0x5C, 0x36,
-+ 0x9D, 0x9E, 0x6D, 0x78, 0x78, 0x78, 0x97, 0x6E,
-+ 0x9F, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, 0xA0,
-+ 0x61, 0x51, 0x51, 0x3C, 0x4C, 0x55, 0x35, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x3B, 0x22,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C,
-+ 0xA1, 0x8D, 0x88, 0x8E, 0xA2, 0xA3, 0x94, 0x42,
-+ 0x51, 0xA4, 0x9A, 0x9A, 0x9A, 0xA5, 0x9C, 0x2A,
-+ 0xA6, 0x74, 0x8C, 0x75, 0x97, 0xA7, 0x76, 0x75,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6E,
-+ 0x46, 0x52, 0x56, 0x3F, 0x42, 0x34, 0x33, 0x35,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x22,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x3A,
-+ 0x5A, 0x53, 0x53, 0x29, 0x43, 0x50, 0x53, 0x5A,
-+ 0x5A, 0x29, 0x5A, 0x43, 0x53, 0x5D, 0x44, 0x2A,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
-+ 0x7D, 0x87, 0x8E, 0x93, 0xA8, 0xA9, 0xAA, 0x2A,
-+ 0x57, 0x94, 0xA4, 0x9B, 0xAB, 0xAC, 0x9A, 0x9B,
-+ 0xAD, 0x76, 0x79, 0x78, 0x75, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D,
-+ 0x46, 0x5C, 0x57, 0x56, 0x51, 0x42, 0x4C, 0x55,
-+ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x27,
-+ 0x29, 0x2A, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x30,
-+ 0x59, 0x3D, 0x3D, 0x3D, 0x27, 0x27, 0x26, 0x5D,
-+ 0x27, 0x27, 0x54, 0x37, 0x2E, 0x4A, 0x36, 0x2B,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0xAE, 0x88, 0xAF, 0xB0, 0xAA, 0x2A, 0x39, 0x34,
-+ 0x4C, 0x5C, 0x58, 0xB1, 0xB2, 0xB3, 0xAB, 0xA5,
-+ 0x9A, 0xB4, 0xB5, 0x8C, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80,
-+ 0xB6, 0x38, 0x5C, 0x57, 0x56, 0x3F, 0x42, 0x3B,
-+ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
-+ 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x32,
-+ 0x31, 0x2C, 0x26, 0x2C, 0x33, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34,
-+ 0x32, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x33,
-+ 0x33, 0x55, 0x55, 0x55, 0x23, 0x23, 0x35, 0x23,
-+ 0x23, 0x35, 0x2B, 0x4E, 0x4F, 0x2A, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, 0x38, 0x25,
-+ 0x2C, 0x52, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x55, 0x8A, 0x8F, 0x39, 0x34, 0x3C, 0x57, 0x32,
-+ 0x46, 0x42, 0x52, 0x4A, 0x51, 0xAA, 0xB7, 0xB3,
-+ 0xAB, 0xAC, 0xAC, 0xB8, 0xB9, 0x79, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A,
-+ 0xBA, 0x70, 0x7B, 0xBB, 0x82, 0x56, 0x3F, 0x34,
-+ 0x4C, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x36,
-+ 0x2D, 0x37, 0x38, 0x2A, 0x2B, 0x21, 0x21, 0x21,
-+ 0x21, 0x22, 0x39, 0x3A, 0x2C, 0x3B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x22, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x24, 0x3D,
-+ 0x3E, 0x25, 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x33, 0x29, 0x26, 0x2A, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x54, 0x3E, 0x28,
-+ 0x28, 0x59, 0x59, 0x48, 0x51, 0x3F, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x2B, 0x56, 0x4D, 0x29, 0x5B, 0x34,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x55, 0x60, 0x3F, 0x42, 0x51, 0x32, 0x52,
-+ 0x40, 0x38, 0x40, 0x46, 0x42, 0xBC, 0xBD, 0xBE,
-+ 0xBF, 0x9B, 0xAB, 0x9B, 0xC0, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
-+ 0xA7, 0x63, 0x63, 0x66, 0x6F, 0x58, 0x56, 0x39,
-+ 0x34, 0x2B, 0x23, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x2F,
-+ 0x3D, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x40, 0x41, 0x3B, 0x21,
-+ 0x21, 0x22, 0x42, 0x38, 0x43, 0x44, 0x3A, 0x45,
-+ 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x46, 0x30, 0x47,
-+ 0x2A, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x22,
-+ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x22, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x22, 0x4D, 0x44, 0x2A, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x50, 0x4A, 0x57, 0x35,
-+ 0x35, 0x2B, 0x56, 0x27, 0x4B, 0x5D, 0x35, 0x21,
-+ 0x21, 0x21, 0x21, 0x3B, 0x52, 0x23, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
-+ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x38,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
-+ 0x3C, 0x42, 0x21, 0x33, 0x24, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
-+ 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x33, 0x38, 0x59, 0x37, 0x27, 0x27, 0x4A, 0x47,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x23, 0x4C, 0x4C, 0x2A, 0x56, 0x46, 0x31,
-+ 0x4D, 0x36, 0x50, 0x5A, 0x35, 0xC1, 0xC1, 0xC2,
-+ 0xC3, 0xB7, 0xB3, 0xBE, 0x76, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
-+ 0x6D, 0x62, 0x69, 0x6F, 0x58, 0x46, 0x32, 0x2A,
-+ 0x39, 0x34, 0x35, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x49,
-+ 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x23, 0x29, 0x48, 0x22,
-+ 0x42, 0x3A, 0x4A, 0x49, 0x4B, 0x2E, 0x4B, 0x3E,
-+ 0x4A, 0x2C, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x30, 0x40, 0x22,
-+ 0x21, 0x32, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x39,
-+ 0x36, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22,
-+ 0x31, 0x4F, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x31, 0x59, 0x2A, 0x22, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x55, 0x27, 0x24, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x4C, 0x44, 0x27, 0x35, 0x21,
-+ 0x21, 0x21, 0x21, 0x2A, 0x26, 0x2B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3A,
-+ 0x40, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, 0x49,
-+ 0x35, 0x21, 0x21, 0x21, 0x21, 0x22, 0x58, 0x25,
-+ 0x5A, 0x57, 0x21, 0x4C, 0x3D, 0x34, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38,
-+ 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x3A, 0x4B, 0x53, 0x56, 0x55, 0x33, 0x42, 0x56,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x55, 0x4C, 0x42, 0x2A, 0x57, 0x5C, 0x38,
-+ 0x36, 0x47, 0x5A, 0xB6, 0x77, 0xC4, 0xC1, 0xC1,
-+ 0xC4, 0xC5, 0xB7, 0xB9, 0x79, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
-+ 0x97, 0xC6, 0x68, 0x57, 0x4D, 0x38, 0x46, 0x32,
-+ 0x51, 0x42, 0x2B, 0x35, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x2D, 0x38,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x3C,
-+ 0x47, 0x4F, 0x50, 0x51, 0x3F, 0x44, 0x42, 0x34,
-+ 0x52, 0x53, 0x28, 0x2A, 0x22, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x48, 0x54, 0x33, 0x21,
-+ 0x23, 0x3A, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x2A,
-+ 0x26, 0x33, 0x21, 0x21, 0x21, 0x21, 0x23, 0x45,
-+ 0x37, 0x3D, 0x41, 0x22, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x31,
-+ 0x59, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x3C, 0x28, 0x33, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x23, 0x27, 0x5B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x3C, 0x54, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B,
-+ 0x46, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x49,
-+ 0x2B, 0x21, 0x21, 0x21, 0x23, 0x40, 0x43, 0x32,
-+ 0x35, 0x21, 0x21, 0x33, 0x28, 0x4C, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x4F,
-+ 0x5B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x50,
-+ 0x44, 0x39, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x23, 0x3B, 0x34, 0x3F, 0x58, 0x46, 0x40, 0x36,
-+ 0x50, 0x41, 0x4D, 0xC7, 0x65, 0xC2, 0xC1, 0xC1,
-+ 0xC8, 0xBF, 0xB1, 0x97, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79,
-+ 0x80, 0xC9, 0x36, 0x50, 0x36, 0x38, 0x31, 0x32,
-+ 0x56, 0x39, 0x34, 0x33, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x2B, 0x3D, 0x28, 0x35,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x4D,
-+ 0x55, 0x2B, 0x21, 0x21, 0x2B, 0x28, 0x3B, 0x21,
-+ 0x21, 0x22, 0x52, 0x27, 0x56, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x23, 0x2A, 0x30, 0x3F, 0x21, 0x22,
-+ 0x57, 0x44, 0x58, 0x21, 0x21, 0x21, 0x21, 0x56,
-+ 0x37, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x56, 0x3E,
-+ 0x36, 0x2A, 0x59, 0x23, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x50, 0x3D,
-+ 0x42, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x56, 0x49, 0x24, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x42, 0x54, 0x33, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x59,
-+ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x4A,
-+ 0x51, 0x21, 0x21, 0x33, 0x47, 0x47, 0x33, 0x21,
-+ 0x21, 0x21, 0x21, 0x55, 0x27, 0x3B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x4B,
-+ 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, 0x44,
-+ 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x33, 0x4C, 0x3C, 0x51, 0x57, 0x5C, 0x38, 0x38,
-+ 0x9D, 0xCA, 0x61, 0xCB, 0xCC, 0xCD, 0xC4, 0xC8,
-+ 0xA4, 0x9C, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79,
-+ 0x7A, 0x7F, 0x41, 0x29, 0x47, 0x38, 0x40, 0x57,
-+ 0x32, 0x51, 0x42, 0x2B, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x57, 0x49, 0x32, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, 0x27,
-+ 0x35, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x2A, 0x21,
-+ 0x21, 0x21, 0x21, 0x56, 0x54, 0x2B, 0x21, 0x21,
-+ 0x21, 0x21, 0x4C, 0x2E, 0x5A, 0x23, 0x55, 0x5B,
-+ 0x49, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x21, 0x32,
-+ 0x3E, 0x3B, 0x21, 0x21, 0x21, 0x35, 0x54, 0x53,
-+ 0x23, 0x55, 0x4F, 0x55, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x25, 0x44, 0x42,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x23, 0x41, 0x46, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x23, 0x53, 0x2F, 0x2A, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x32, 0x28, 0x33, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x59, 0x5B,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54,
-+ 0x57, 0x21, 0x35, 0x53, 0x47, 0x23, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x3C, 0x44, 0x3B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x41, 0x43,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3F, 0x29,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x55, 0x4C, 0x3F, 0x2A, 0x46, 0x31, 0x36, 0x46,
-+ 0x71, 0x97, 0xCE, 0xCB, 0xCF, 0xA4, 0x9C, 0xA4,
-+ 0xAD, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x8C,
-+ 0x7A, 0xA7, 0x36, 0x50, 0x3A, 0x36, 0x38, 0x52,
-+ 0x32, 0x2A, 0x3F, 0x2B, 0x22, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x22, 0x5A, 0x5A, 0x23, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x28,
-+ 0x35, 0x21, 0x21, 0x21, 0x55, 0x30, 0x56, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x5B, 0x45, 0x21, 0x21,
-+ 0x21, 0x21, 0x2B, 0x2E, 0x25, 0x47, 0x3D, 0x2D,
-+ 0x25, 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39,
-+ 0x44, 0x55, 0x21, 0x21, 0x21, 0x46, 0x59, 0x3B,
-+ 0x21, 0x23, 0x30, 0x34, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x2A, 0x28, 0x4E, 0x42, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x3C, 0x3D, 0x42, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x51, 0x4B, 0x49, 0x39, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x5C, 0x25, 0x23, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x4B, 0x3B,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54,
-+ 0x56, 0x21, 0x5B, 0x3A, 0x35, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x51, 0x59, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x2D, 0x42,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A,
-+ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x2B, 0x3C, 0x39, 0x56, 0x46, 0x40, 0x36, 0xB6,
-+ 0x73, 0x82, 0xCB, 0xD0, 0x75, 0xD1, 0xD2, 0xD1,
-+ 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x74, 0xCE,
-+ 0x9E, 0x6E, 0xD3, 0xC6, 0x6F, 0x81, 0x38, 0x5C,
-+ 0x52, 0x58, 0x39, 0x4C, 0x35, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x4C, 0x4A, 0x40, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x3A,
-+ 0x21, 0x21, 0x21, 0x21, 0x55, 0x27, 0x3F, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x3B, 0x21,
-+ 0x21, 0x21, 0x42, 0x2E, 0x2D, 0x2D, 0x26, 0x46,
-+ 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51,
-+ 0x44, 0x55, 0x21, 0x21, 0x35, 0x25, 0x40, 0x21,
-+ 0x21, 0x22, 0x4E, 0x58, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x39, 0x59, 0x38, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x56, 0x59, 0x23, 0x21, 0x21, 0x21,
-+ 0x21, 0x4C, 0x54, 0x5B, 0x59, 0x4C, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x57, 0x3A, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x4D, 0x49, 0x26, 0x23,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x53,
-+ 0x32, 0x51, 0x27, 0x42, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x42, 0x25, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x24, 0x37, 0x3E, 0x35,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x48,
-+ 0x48, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
-+ 0x3B, 0x39, 0x3F, 0x32, 0x5C, 0x38, 0x47, 0xD4,
-+ 0x7A, 0xC7, 0xCB, 0xD0, 0x74, 0x80, 0x8C, 0x9F,
-+ 0x80, 0x79, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x73, 0x72, 0xD5, 0xCA, 0x61, 0xD3, 0x40, 0x5C,
-+ 0x46, 0x58, 0x51, 0x42, 0x33, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x39, 0x4B, 0x58, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x2A, 0x3D, 0x51,
-+ 0x21, 0x21, 0x21, 0x21, 0x55, 0x28, 0x42, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, 0x52, 0x21,
-+ 0x21, 0x21, 0x58, 0x59, 0x42, 0x3C, 0x35, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57,
-+ 0x4E, 0x23, 0x21, 0x22, 0x4D, 0x54, 0x35, 0x21,
-+ 0x21, 0x21, 0x5A, 0x46, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x22, 0x56, 0x59, 0x36, 0x35, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x36, 0x5B, 0x21, 0x21, 0x21, 0x21,
-+ 0x23, 0x53, 0x48, 0x3F, 0x27, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x24, 0x47, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x22, 0x40, 0x27, 0x29, 0x29, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47,
-+ 0x40, 0x41, 0x5C, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x39, 0x41, 0x23, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x32, 0x26, 0x47, 0x28, 0x22,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
-+ 0x53, 0x28, 0x36, 0x42, 0x23, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x4C, 0x39, 0x58, 0x32, 0x31, 0x38, 0x47, 0xD4,
-+ 0xCF, 0xD0, 0x6C, 0x9E, 0xD6, 0x6B, 0xD7, 0xD8,
-+ 0xD7, 0x6B, 0xCF, 0x7B, 0x80, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x74, 0x72, 0xD0, 0xA6, 0x70, 0x51,
-+ 0x46, 0x56, 0x51, 0x42, 0x55, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x5C, 0x27, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x32, 0x37, 0x54, 0x33,
-+ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x2A, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x2C, 0x21,
-+ 0x21, 0x21, 0x47, 0x36, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52,
-+ 0x54, 0x23, 0x21, 0x24, 0x4F, 0x46, 0x21, 0x21,
-+ 0x21, 0x21, 0x38, 0x2C, 0x22, 0x21, 0x21, 0x21,
-+ 0x21, 0x42, 0x55, 0x21, 0x21, 0x21, 0x21, 0x33,
-+ 0x45, 0x54, 0x56, 0x22, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x22, 0x53, 0x24, 0x21, 0x21, 0x21, 0x21,
-+ 0x46, 0x5D, 0x4C, 0x52, 0x4E, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x31, 0x48, 0x22, 0x21, 0x21,
-+ 0x21, 0x22, 0x46, 0x54, 0x3B, 0x45, 0x29, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47,
-+ 0x28, 0x28, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x51, 0x41, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x56, 0x54, 0x39, 0x56, 0x28, 0x22,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x23, 0x34, 0x50, 0x30, 0x4E, 0x40, 0x34, 0x22,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x4C, 0x39, 0x58, 0x52, 0x5C, 0x38, 0x47, 0x9D,
-+ 0xC9, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC,
-+ 0xDC, 0xDC, 0xDC, 0xDD, 0x6B, 0x7B, 0x75, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x74, 0x71, 0xD0, 0x3F,
-+ 0x52, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x47, 0x3A, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x35, 0x45, 0x4A, 0x2C, 0x3B, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x30, 0x56, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x58, 0x29, 0x21,
-+ 0x21, 0x21, 0x53, 0x3F, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31,
-+ 0x43, 0x22, 0x3B, 0x28, 0x48, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x56, 0x25, 0x35, 0x21, 0x21, 0x21,
-+ 0x39, 0x54, 0x34, 0x21, 0x21, 0x21, 0x35, 0x3A,
-+ 0x30, 0x57, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x33, 0x39, 0x21, 0x21,
-+ 0x21, 0x35, 0x25, 0x3F, 0x21, 0x21, 0x21, 0x56,
-+ 0x30, 0x58, 0x21, 0x24, 0x43, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x4D, 0x29, 0x22, 0x21, 0x21,
-+ 0x22, 0x32, 0x26, 0x42, 0x21, 0x46, 0x2C, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x48,
-+ 0x2E, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x56, 0x28, 0x35, 0x21, 0x21,
-+ 0x21, 0x3F, 0x27, 0x32, 0x21, 0x51, 0x25, 0x22,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x22, 0x39, 0x38, 0x25, 0x54, 0x50,
-+ 0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
-+ 0x4C, 0x3F, 0x56, 0x52, 0x31, 0x4D, 0x47, 0x39,
-+ 0xD8, 0xDC, 0xDC, 0xDC, 0xDE, 0xDF, 0xDF, 0xDF,
-+ 0xDF, 0xDF, 0xDE, 0xDE, 0xDC, 0xDD, 0xD6, 0x97,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x97, 0x56,
-+ 0x46, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x38, 0x29, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x35, 0x5B, 0x3D, 0x40, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x3F, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21,
-+ 0x21, 0x22, 0x5D, 0x34, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x5B,
-+ 0x2C, 0x33, 0x29, 0x28, 0x3B, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x34, 0x59, 0x3C, 0x21, 0x21, 0x2B,
-+ 0x53, 0x36, 0x22, 0x21, 0x21, 0x34, 0x5A, 0x28,
-+ 0x3F, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x40, 0x41, 0x23, 0x21,
-+ 0x21, 0x3B, 0x28, 0x2B, 0x21, 0x21, 0x2A, 0x44,
-+ 0x38, 0x22, 0x21, 0x24, 0x50, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x50, 0x25, 0x23, 0x21, 0x23,
-+ 0x45, 0x5D, 0x52, 0x21, 0x21, 0x40, 0x50, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x50,
-+ 0x2D, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x46, 0x30, 0x33, 0x21, 0x22,
-+ 0x24, 0x4E, 0x45, 0x22, 0x21, 0x58, 0x25, 0x22,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x48,
-+ 0x27, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x34, 0x3F, 0x58, 0x57, 0x31, 0x4D, 0x47, 0x56,
-+ 0xDB, 0xDC, 0xDE, 0xE0, 0xE1, 0xE2, 0xE2, 0xE2,
-+ 0xE2, 0xE2, 0xE1, 0xE3, 0xE4, 0xDE, 0xDC, 0x6B,
-+ 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0xA7, 0x38,
-+ 0x46, 0x56, 0x2A, 0x39, 0x3B, 0x23, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x32, 0x44, 0x34, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3F,
-+ 0x4D, 0x41, 0x29, 0x42, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x46, 0x34,
-+ 0x2B, 0x55, 0x55, 0x2B, 0x56, 0x59, 0x36, 0x21,
-+ 0x21, 0x22, 0x59, 0x2B, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x55, 0x5C, 0x21, 0x21, 0x21, 0x40,
-+ 0x50, 0x4D, 0x4F, 0x32, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x55, 0x44, 0x31, 0x22, 0x3B, 0x5A,
-+ 0x41, 0x55, 0x21, 0x35, 0x57, 0x4A, 0x2E, 0x48,
-+ 0x57, 0x32, 0x3F, 0x55, 0x35, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x25, 0x47, 0x22, 0x21,
-+ 0x21, 0x4C, 0x28, 0x35, 0x21, 0x34, 0x30, 0x3A,
-+ 0x23, 0x21, 0x21, 0x58, 0x3A, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x4D, 0x4E, 0x35, 0x33, 0x48,
-+ 0x44, 0x56, 0x21, 0x21, 0x21, 0x58, 0x41, 0x23,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x29,
-+ 0x4A, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x32, 0x44, 0x2B, 0x23, 0x45,
-+ 0x3D, 0x31, 0x22, 0x21, 0x21, 0x4C, 0x27, 0x35,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x53, 0x53, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x34, 0x3F, 0x58, 0x57, 0x40, 0x38, 0x47, 0xD4,
-+ 0xDC, 0xDE, 0xE0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE1, 0xDF, 0xDC,
-+ 0xE6, 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x2A, 0x40,
-+ 0x46, 0x58, 0x2A, 0x42, 0x34, 0x34, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x2B, 0x54, 0x5A, 0x34, 0x23,
-+ 0x35, 0x23, 0x35, 0x33, 0x2B, 0x24, 0x54, 0x4B,
-+ 0x59, 0x5C, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, 0x44, 0x59,
-+ 0x27, 0x26, 0x26, 0x4A, 0x3E, 0x41, 0x55, 0x21,
-+ 0x21, 0x22, 0x41, 0x39, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x34, 0x53, 0x4D, 0x21, 0x21, 0x21, 0x5C,
-+ 0x4B, 0x4F, 0x40, 0x22, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x48, 0x30, 0x50, 0x26, 0x54,
-+ 0x34, 0x21, 0x55, 0x4E, 0x2D, 0x2F, 0x4F, 0x37,
-+ 0x3E, 0x4B, 0x4B, 0x30, 0x27, 0x53, 0x2C, 0x57,
-+ 0x42, 0x4C, 0x55, 0x22, 0x22, 0x22, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x39, 0x4A, 0x3F, 0x21, 0x21,
-+ 0x21, 0x55, 0x53, 0x55, 0x2A, 0x26, 0x54, 0x33,
-+ 0x21, 0x21, 0x21, 0x51, 0x54, 0x3B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x51, 0x3D, 0x46, 0x5A, 0x4F,
-+ 0x52, 0x21, 0x21, 0x21, 0x21, 0x22, 0x27, 0x31,
-+ 0x33, 0x23, 0x42, 0x4C, 0x21, 0x21, 0x21, 0x5B,
-+ 0x54, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x3B, 0x44, 0x45, 0x48, 0x4B,
-+ 0x38, 0x22, 0x21, 0x21, 0x21, 0x21, 0x53, 0x48,
-+ 0x33, 0x23, 0x34, 0x3C, 0x22, 0x57, 0x4D, 0x33,
-+ 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x34, 0x40,
-+ 0x44, 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x3B, 0x42, 0x2A, 0x57, 0x31, 0x38, 0x5C, 0xD8,
-+ 0xDC, 0xE4, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE0,
-+ 0xDE, 0xCA, 0x9F, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x80, 0x76, 0x57, 0x5C,
-+ 0x31, 0x6E, 0x34, 0x3C, 0xC9, 0x3B, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x33, 0x5B, 0x30, 0x25,
-+ 0x5D, 0x5A, 0x53, 0x27, 0x26, 0x59, 0x36, 0x56,
-+ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x3D, 0x2A, 0x55,
-+ 0x42, 0x51, 0x56, 0x24, 0x2A, 0x35, 0x21, 0x21,
-+ 0x21, 0x21, 0x45, 0x53, 0x3B, 0x22, 0x22, 0x35,
-+ 0x46, 0x59, 0x54, 0x55, 0x21, 0x21, 0x21, 0x31,
-+ 0x2D, 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x33, 0x50, 0x5D, 0x45, 0x55,
-+ 0x21, 0x21, 0x34, 0x4F, 0x29, 0x58, 0x33, 0x4C,
-+ 0x39, 0x3C, 0x2A, 0x40, 0x48, 0x54, 0x3D, 0x3D,
-+ 0x37, 0x4A, 0x59, 0x29, 0x5B, 0x36, 0x52, 0x2A,
-+ 0x42, 0x3C, 0x32, 0x30, 0x41, 0x35, 0x21, 0x21,
-+ 0x21, 0x33, 0x41, 0x26, 0x4B, 0x5A, 0x35, 0x21,
-+ 0x21, 0x21, 0x21, 0x3C, 0x3E, 0x41, 0x23, 0x21,
-+ 0x21, 0x21, 0x21, 0x23, 0x41, 0x49, 0x30, 0x32,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x4F,
-+ 0x5D, 0x41, 0x27, 0x58, 0x21, 0x21, 0x21, 0x5B,
-+ 0x41, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x47, 0x49, 0x4F, 0x5C,
-+ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, 0x4A,
-+ 0x28, 0x43, 0x27, 0x5C, 0x35, 0x25, 0x49, 0x5B,
-+ 0x58, 0x52, 0x5C, 0x38, 0x48, 0x41, 0x4A, 0x4B,
-+ 0x50, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
-+ 0x3B, 0x3C, 0x2A, 0x32, 0x5C, 0x40, 0x32, 0xDD,
-+ 0xDC, 0xE3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE1, 0xE0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x80, 0xE7, 0x58, 0x52,
-+ 0x5C, 0x67, 0xE7, 0x6C, 0xE8, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x23, 0x39, 0x5C,
-+ 0x29, 0x5A, 0x4D, 0x5C, 0x2A, 0x2B, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x42, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x33, 0x27, 0x30, 0x5A, 0x2C, 0x25,
-+ 0x4B, 0x50, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x33,
-+ 0x2C, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x4C, 0x22, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x55, 0x2B,
-+ 0x39, 0x32, 0x4D, 0x29, 0x26, 0x3D, 0x2D, 0x2D,
-+ 0x4B, 0x4B, 0x2F, 0x30, 0x42, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x3B, 0x29, 0x2C, 0x55, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x23, 0x50, 0x4D, 0x22, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x32, 0x3B, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51,
-+ 0x48, 0x45, 0x34, 0x21, 0x21, 0x21, 0x21, 0x38,
-+ 0x44, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x33, 0x32, 0x34, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3C,
-+ 0x5B, 0x4D, 0x42, 0x21, 0x21, 0x34, 0x4D, 0x47,
-+ 0x5A, 0x5D, 0x27, 0x4E, 0x25, 0x3A, 0x5C, 0x42,
-+ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
-+ 0x2B, 0x34, 0x51, 0x56, 0x46, 0x40, 0xE9, 0xDA,
-+ 0xDD, 0xE1, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE2, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x76, 0xD3, 0x67, 0x39,
-+ 0x3C, 0xCF, 0xD5, 0x9F, 0x3B, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x2B, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x3C, 0x53, 0x44, 0x3D, 0x43,
-+ 0x57, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x35, 0x55, 0x3F, 0x2A,
-+ 0x57, 0x24, 0x3F, 0x3B, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
-+ 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x55, 0x4C, 0x3F, 0x58, 0x46, 0x31, 0x8B, 0xAD,
-+ 0xCC, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x97, 0x35, 0x6E, 0xC6, 0x82,
-+ 0xA6, 0x73, 0x75, 0xBA, 0x2B, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x34, 0x44, 0x3B, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x33, 0x34, 0xEB, 0x34, 0x57, 0x5C, 0x4C, 0xA4,
-+ 0xEC, 0x64, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0x83, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x80, 0xED, 0xCF, 0xCE, 0x78, 0x78,
-+ 0x78, 0x7A, 0x6D, 0x34, 0x22, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x55, 0x25, 0x55, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x23, 0x34, 0xEE, 0xEF, 0x5F, 0x96, 0x23, 0xB3,
-+ 0xBF, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x9F, 0x78, 0x78, 0x78, 0x78,
-+ 0x80, 0x9F, 0x65, 0x33, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x55, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x22, 0x4C, 0xF1, 0xA5, 0xAC, 0xAB, 0x60, 0xB3,
-+ 0xB3, 0xF2, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xF3, 0x6D, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x80, 0x61, 0x34, 0x23, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x22, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5E,
-+ 0x4C, 0x3B, 0xF4, 0xA5, 0x9B, 0x9B, 0xB4, 0xEF,
-+ 0xEF, 0xBF, 0xAD, 0xF5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0x67, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80,
-+ 0xA7, 0x3F, 0x55, 0x22, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x23, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5F,
-+ 0x9B, 0xD2, 0x3C, 0xB7, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0xF0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x82,
-+ 0x34, 0x3B, 0x33, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x5D, 0x23, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x60,
-+ 0xAB, 0xA5, 0xB8, 0xB1, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xF6, 0xB7, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
-+ 0x67, 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x78, 0x80, 0x9F, 0xBA, 0x42,
-+ 0x4C, 0x2B, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
-+ 0xF2, 0x9B, 0x9B, 0xB4, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xEF, 0xB4, 0x5F, 0x63, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF5,
-+ 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x78, 0x78, 0x80, 0x6D, 0x65, 0x3C, 0x34,
-+ 0x3B, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
-+ 0xF7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5,
-+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF8, 0x68,
-+ 0x7A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x78, 0x80, 0x97, 0x82, 0x39, 0x39, 0x34, 0x3B,
-+ 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x3B, 0xB8, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xEF, 0xF6, 0xB2, 0xF9, 0xFA, 0xFA, 0xFA,
-+ 0xFA, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0x6F, 0x97,
-+ 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-+ 0x8C, 0x61, 0x39, 0x2A, 0x3F, 0x3C, 0x4C, 0x55,
-+ 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x31, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x22, 0xFB, 0xF6, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xEF, 0xB3, 0xB2, 0xF9, 0xF3, 0xF3, 0xF3,
-+ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0x90, 0x6D, 0x97,
-+ 0x8C, 0x6D, 0x76, 0xBB, 0xC6, 0xB9, 0xC0, 0xFC,
-+ 0xAD, 0xFB, 0x2A, 0x58, 0x42, 0x4C, 0x55, 0x33,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x33, 0xD2, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
-+ 0xEF, 0xEF, 0xB4, 0xB8, 0xEB, 0xE8, 0x7F, 0xD6,
-+ 0xD6, 0xD6, 0xD6, 0x9D, 0x9D, 0x52, 0xEB, 0x5F,
-+ 0x5F, 0x5F, 0xF2, 0xA4, 0xBF, 0xBF, 0xB4, 0xBF,
-+ 0xEE, 0x56, 0x2A, 0x42, 0x4C, 0x2B, 0x33, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x4C, 0xBE, 0xF6, 0xEF, 0xEF, 0xEF,
-+ 0xF6, 0xB4, 0xB2, 0xF1, 0x3C, 0x56, 0x46, 0x5C,
-+ 0x31, 0x38, 0x40, 0x40, 0x4D, 0x4D, 0xB8, 0xAC,
-+ 0xBF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB4,
-+ 0xB1, 0x39, 0x39, 0x3B, 0x2B, 0x23, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x3B, 0xAD, 0xA4, 0xBF, 0xBF,
-+ 0xB7, 0xB2, 0xEE, 0x5E, 0x39, 0x51, 0x2A, 0x32,
-+ 0x52, 0x46, 0x5C, 0x31, 0x31, 0x2A, 0xA5, 0xEF,
-+ 0xFD, 0xB4, 0xEF, 0xF6, 0xF6, 0xEF, 0xF6, 0xB2,
-+ 0x3F, 0x34, 0x2B, 0x55, 0x23, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x33, 0xEB, 0xF7, 0xAA,
-+ 0xAA, 0xF7, 0xEB, 0x55, 0x3B, 0x3C, 0x39, 0x51,
-+ 0x2A, 0x56, 0x32, 0x57, 0x57, 0x2A, 0x96, 0x3C,
-+ 0x2A, 0xEE, 0xEF, 0x5F, 0xD2, 0xEF, 0xB4, 0xAA,
-+ 0x42, 0x55, 0x35, 0x22, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3B,
-+ 0x3B, 0x35, 0x21, 0x23, 0x33, 0x3B, 0x4C, 0x3C,
-+ 0x39, 0x3F, 0x51, 0x2A, 0x51, 0x51, 0x58, 0x32,
-+ 0x56, 0xF4, 0xB1, 0x42, 0x3C, 0xF2, 0x9C, 0x3F,
-+ 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x33, 0x55,
-+ 0x3B, 0x4C, 0x4C, 0x3C, 0x42, 0x42, 0x3C, 0x34,
-+ 0x34, 0x3F, 0x4C, 0x3B, 0x4C, 0x3B, 0x3C, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x35, 0x33, 0x55, 0x33, 0x33, 0x33, 0x55, 0x2B,
-+ 0x2B, 0x35, 0x35, 0x35, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
-+ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
- };
-
- #endif /* !__HAVE_ARCH_LINUX_LOGO */
-@@ -994,7 +1760,7 @@
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
-
- #endif /* !__HAVE_ARCH_LINUX_LOGOBW */
-@@ -1401,7 +2167,7 @@
- 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
- };
-
- #endif /* !__HAVE_ARCH_LINUX_LOGO16 */
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch
deleted file mode 100644
index 4daeaa11be..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-
-#
-# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
-#
-
---- linux/Makefile~mkdep 2003-12-19 09:36:51.000000000 -0800
-+++ linux/Makefile 2003-12-19 09:57:44.000000000 -0800
-@@ -458,7 +458,7 @@
-
- dep-files: scripts/mkdep archdep include/linux/version.h
- scripts/mkdep -- init/*.c > .depend
-- scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
-+ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)
- $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
- ifdef CONFIG_MODVERSIONS
- $(MAKE) update-modverfile
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/module_licence.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/module_licence.patch
deleted file mode 100644
index fc20f0d281..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/module_licence.patch
+++ /dev/null
@@ -1,81 +0,0 @@
---- linux/drivers/usb/device/bi/sa1100.c.orig 2003-05-13 11:18:44.000000000 +0200
-+++ linux/drivers/usb/device/bi/sa1100.c 2004-08-01 13:49:10.000000000 +0200
-@@ -46,6 +46,7 @@
- #include "../usbd-build.h"
- #include "../usbd-module.h"
-
-+MODULE_LICENSE("GPL");
- MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
- MODULE_DESCRIPTION ("USB Device SA-1100 Bus Interface");
-
---- linux/drivers/usb/device/usbd.c.orig 2003-05-13 11:18:45.000000000 +0200
-+++ linux/drivers/usb/device/usbd.c 2004-08-01 13:47:47.000000000 +0200
-@@ -72,6 +72,7 @@
- #include "usbd-build.h"
- #include "usbd-module.h"
-
-+MODULE_LICENSE("GPL");
- MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
- MODULE_DESCRIPTION ("USB Device Core Support");
-
---- linux/drivers/usb/device/usbd-monitor.c.orig 2004-08-01 13:46:44.000000000 +0200
-+++ linux/drivers/usb/device/usbd-monitor.c 2004-08-01 13:46:36.000000000 +0200
-@@ -33,6 +33,7 @@
- #include "usbd-build.h"
- #include "usbd-module.h"
-
-+MODULE_LICENSE("GPL");
- MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
- MODULE_DESCRIPTION ("USB Device Monitor");
- USBD_MODULE_INFO ("usbd_monitor 0.3");
---- linux/drivers/usb/device/net_fd/net-fd.c.orig 2003-05-13 11:18:45.000000000 +0200
-+++ linux/drivers/usb/device/net_fd/net-fd.c 2004-08-01 13:48:32.000000000 +0200
-@@ -33,6 +33,7 @@
- #include "../usbd-build.h"
- #include "../usbd-module.h"
-
-+MODULE_LICENSE("GPL");
- MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
- MODULE_DESCRIPTION ("USB Device Network Function");
-
---- linux/arch/arm/mach-sa1100/deviceinfo.c.orig 2004-08-01 13:56:24.000000000 +0200
-+++ linux/arch/arm/mach-sa1100/deviceinfo.c 2004-08-01 13:56:11.000000000 +0200
-@@ -28,6 +28,7 @@
-
- #define MODULE_NAME "deviceinfo"
- #define DEVINFO_DIRNAME "deviceinfo"
-+MODULE_LICENSE("GPL");
-
- static int proc_read_deviceinfo(struct file * file, char * buf,
- size_t nbytes, loff_t *ppos);
---- linux/arch/arm/mach-sa1100/gpio.c.orig 2003-05-13 11:18:14.000000000 +0200
-+++ linux/arch/arm/mach-sa1100/gpio.c 2004-08-01 13:55:27.000000000 +0200
-@@ -15,7 +15,7 @@
-
- #include <asm/hardware.h>
-
--
-+MODULE_LICENSE("GPL");
-
- static int proc_gpio_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
---- linux/drivers/usb/device/serial_fd/serial.c.orig 2003-05-13 11:18:45.000000000 +0200
-+++ linux/drivers/usb/device/serial_fd/serial.c 2004-08-01 14:25:02.000000000 +0200
-@@ -80,6 +80,7 @@
- #include "../usbd-module.h"
-
-
-+MODULE_LICENSE("GPL");
- MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
- MODULE_DESCRIPTION ("USB Device Serial Function");
-
---- linux/drivers/usb/device/usbd-serialnumber.c.orig 2003-05-13 11:18:45.000000000 +0200
-+++ linux/drivers/usb/device/usbd-serialnumber.c 2004-08-01 14:25:40.000000000 +0200
-@@ -33,6 +33,7 @@
- #include "usbd-build.h"
- #include "usbd-module.h"
-
-+MODULE_LICENSE("GPL");
- MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
- MODULE_DESCRIPTION ("USB Device Monitor");
- USBD_MODULE_INFO ("usbd_monitor 0.2-alpha");
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch
deleted file mode 100644
index d75c07a1c8..0000000000
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch
+++ /dev/null
@@ -1,5602 +0,0 @@
-diff -Nuar linux-2.4.18/arch/arm/mach-sa1100/m62332.c linux-2.4.18p/arch/arm/mach-sa1100/m62332.c
---- linux-2.4.18/arch/arm/mach-sa1100/m62332.c 2003-05-13 11:18:14.000000000 +0200
-+++ linux-2.4.18p/arch/arm/mach-sa1100/m62332.c 2004-10-12 22:36:36.000000000 +0200
-@@ -131,3 +131,5 @@
-
- return 0;
- }
-+EXPORT_SYMBOL(m62332_senddata);
-+
-diff -Nuar linux-2.4.18/arch/arm/mach-sa1100/Makefile linux-2.4.18p/arch/arm/mach-sa1100/Makefile
---- linux-2.4.18/arch/arm/mach-sa1100/Makefile 2003-05-13 11:18:14.000000000 +0200
-+++ linux-2.4.18p/arch/arm/mach-sa1100/Makefile 2004-10-12 22:36:19.000000000 +0200
-@@ -18,7 +18,7 @@
- export-objs := assabet.o consus.o badge4.o dma-sa1100.o dma-sa1111.o \
- flexanet.o freebird.o generic.o h3600.o \
- huw_webpanel.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \
-- system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o
-+ system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o m62332.o
-
- # These aren't present yet, and prevents a plain -ac kernel building.
- # hwtimer.o
-@@ -36,7 +36,7 @@
- obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o
- endif
-
--obj-$(CONFIG_SA1100_COLLIE) += collie.o m62332.o collie_battery.o collie_led.o collie_buzzer.o
-+obj-$(CONFIG_SA1100_COLLIE) += collie.o m62332.o collie_battery.o collie_led.o
-
- # Next, the SA1111 stuff.
- obj-$(CONFIG_SA1111) += sa1111.o dma-sa1111.o
-diff -Nuar linux-2.4.18/drivers/char/Makefile linux-2.4.18p/drivers/char/Makefile
---- linux-2.4.18/drivers/char/Makefile 2003-05-13 11:18:18.000000000 +0200
-+++ linux-2.4.18p/drivers/char/Makefile 2004-10-12 17:26:44.000000000 +0200
-@@ -228,7 +228,7 @@
- obj-y += joystick/js.o
- endif
-
--obj-$(CONFIG_SA1100_COLLIE) += sharp_led.o sharp_kbdctl.o sharp_buzzer.o
-+obj-$(CONFIG_SA1100_COLLIE) += sharp_led.o sharp_kbdctl.o
- obj-$(CONFIG_DISCOVERY_LED) += sharp_led.o discovery_led.o
- obj-$(CONFIG_ARCH_PXA_POODLE) += sharp_led.o sharp_kbdctl.o sharpsl_led.o sharp_buzzer.o
- obj-$(CONFIG_ARCH_PXA_CORGI) += sharp_led.o sharpsl_led.o sharp_kbdctl.o corgi_rc.o sharp_buzzer.o
-diff -Nuar linux-2.4.18/drivers/sound/colliebuzzer.h linux-2.4.18p/drivers/sound/colliebuzzer.h
---- linux-2.4.18/drivers/sound/colliebuzzer.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18p/drivers/sound/colliebuzzer.h 2004-10-13 15:24:51.028208808 +0200
-@@ -0,0 +1,756 @@
-+unsigned short tap_data[] = {
-+ 0x0000 , 0xff00 , 0xff00 , 0x0000 ,
-+ 0xff00 , 0x0000 , 0x0000 , 0x0100 ,
-+ 0x0000 , 0x0100 , 0x0000 , 0x0100 ,
-+ 0x0100 , 0x0000 , 0x0100 , 0x0100 ,
-+ 0x0100 , 0x0100 , 0x0100 , 0x0100 ,
-+ 0x0100 , 0x0100 , 0x0100 , 0x0100 ,
-+ 0x0100 , 0x0000 , 0x0100 , 0x0000 ,
-+ 0x0100 , 0xff00 , 0x0100 , 0x0000 ,
-+ 0x0100 , 0x0000 , 0x0000 , 0x0100 ,
-+ 0x0000 , 0x0100 , 0x0000 , 0x0100 ,
-+ 0x0000 , 0x0000 , 0x0000 , 0x0000 ,
-+ 0x0000 , 0x0100 , 0x0000 , 0x0100 ,
-+ 0x0000 , 0x0100 , 0x0700 , 0x1c00 ,
-+ 0xc800 , 0xd900 , 0x2b00 , 0x2700 ,
-+ 0xbf00 , 0xe000 , 0x0d00 , 0x1000 ,
-+ 0xf500 , 0xd700 , 0x0100 , 0x0a00 ,
-+ 0xfb00 , 0xfa00 , 0x2200 , 0x0100 ,
-+ 0xeb00 , 0x0300 , 0x0600 , 0x1600 ,
-+ 0xe500 , 0xf500 , 0x0d00 , 0x0a00 ,
-+ 0x0100 , 0xfb00 , 0x0000 , 0x0100 ,
-+ 0xf200 , 0x0400 , 0x0600 , 0x0000 ,
-+ 0xf100 , 0x0300 , 0x1200 , 0xfe00 ,
-+ 0xe900 , 0x0400 , 0x0100 , 0x0d00 ,
-+ 0xf500 , 0x0100 , 0x0100 , 0xfe00 ,
-+ 0x0100 , 0xfb00 , 0x0400 , 0xff00 ,
-+ 0xf700 , 0x0400 , 0x0000 , 0xfe00 ,
-+ 0x0200 , 0x0000 , 0x0100 , 0xfd00 ,
-+ 0x0000 , 0xff00 , 0x0200 , 0x0000 ,
-+ 0xff00 , 0x0000 , 0x0200 , 0xfc00 ,
-+ 0xfe00 , 0xff00 , 0x0100 , 0x0200 ,
-+ 0x0000 , 0xff00 , 0xfc00 , 0x0100 ,
-+ 0x0100 , 0x0100 , 0xff00 , 0x0000 ,
-+ 0x0300 , 0xfe00 , 0xfe00 , 0x0200 ,
-+ 0xff00 , 0x0000 , 0x0000 , 0xfe00 ,
-+ 0x0000 , 0xff00 , 0x0000 , 0x0000 ,
-+ 0x0000 , 0xff00 , 0x0000 , 0x0000 ,
-+ 0xff00 , 0xfe00 , 0xfd00 , 0x0100 ,
-+ 0x0000 , 0xfe00 , 0xff00 , 0xff00 ,
-+ 0x0000 , 0xff00 , 0x0100 , 0xfe00 ,
-+ 0xff00 , 0xff00 , 0x0000 , 0x0000 ,
-+ 0xfe00 , 0xff00 , 0x0100 , 0x0100 ,
-+ 0xff00 , 0x0100 , 0x0100 , 0xfe00 ,
-+ 0x0000 , 0x0000 , 0x0000 , 0x0100 ,
-+ 0x0000 , 0x0000 , 0xff00 , 0x0000 ,
-+ 0x0100 , 0x0000 , 0x0200 };
-+
-+
-+unsigned short click_data[] = {
-+ 0x0100 , 0x0100 , 0x0100 , 0x0000 ,
-+ 0x0100 , 0xff00 , 0x0100 , 0x0000 ,
-+ 0xff00 , 0xff00 , 0xff00 , 0x0000 ,
-+ 0xff00 , 0xff00 , 0xff00 , 0xff00 ,
-+ 0xff00 , 0xff00 , 0x0000 , 0xff00 ,
-+ 0xff00 , 0xff00 , 0x0000 , 0xff00 ,
-+ 0xff00 , 0xff00 , 0xff00 , 0x0100 ,
-+ 0x0000 , 0xff00 , 0xfe00 , 0x0100 ,
-+ 0xff00 , 0x0100 , 0xff00 , 0x0100 ,
-+ 0x0100 , 0x0300 , 0xff00 , 0xff00 ,
-+ 0xff00 , 0x0100 , 0x0100 , 0x0000 ,
-+ 0xfe00 , 0xfe00 , 0xfe00 , 0xfc00 ,
-+ 0xfe00 , 0x0100 , 0xfd00 , 0xff00 ,
-+ 0xff00 , 0xfc00 , 0xfe00 , 0xfd00 ,
-+ 0x0100 , 0xfe00 , 0x0100 , 0xf800 ,
-+ 0xfe00 , 0xfe00 , 0xfc00 , 0xe600 ,
-+ 0xdb00 , 0x2500 , 0xdb00 , 0xee00 ,
-+ 0xdb00 , 0x0600 , 0xeb00 , 0x1f00 ,
-+ 0x1e00 , 0xeb00 , 0xfe00 , 0x0000 ,
-+ 0xff00 , 0x1900 , 0xef00 , 0xf700 ,
-+ 0x2100 , 0xe400 , 0x0100 , 0x0600 ,
-+ 0xff00 , 0x0300 , 0xf900 , 0x0f00 ,
-+ 0xf600 , 0x0100 , 0xfe00 , 0xf900 ,
-+ 0x0500 , 0xf500 , 0x0600 , 0xfb00 ,
-+ 0x0800 , 0x0100 , 0x0300 , 0x0100 ,
-+ 0xf700 , 0xfa00 , 0xfd00 , 0xfc00 ,
-+ 0x0800 , 0xfb00 , 0x0500 , 0xfe00 ,
-+ 0xfc00 , 0xfc00 , 0xfe00 , 0x0400 ,
-+ 0xff00 , 0xff00 , 0x0500 , 0x0100 ,
-+ 0xfc00 , 0xff00 , 0xfe00 , 0xfb00 ,
-+ 0x0200 , 0x0200 , 0xff00 , 0xfe00 ,
-+ 0xfe00 , 0x0600 , 0xfb00 , 0xff00 ,
-+ 0xfc00 , 0x0600 , 0xfb00 , 0xff00 ,
-+ 0xff00 , 0x0100 , 0xff00 , 0x0200 ,
-+ 0xff00 , 0xfb00 , 0xff00 , 0x0200 ,
-+ 0xff00 , 0x0200 , 0x0100 , 0xfe00 ,
-+ 0xfe00 , 0x0100 , 0xfd00 , 0x0200 ,
-+ 0xfc00 , 0x0800 , 0xfe00 , 0xfe00 ,
-+ 0x0400 , 0xfc00 , 0xff00 , 0xfc00 ,
-+ 0x0500 , 0x0200 , 0x0800 , 0x0200 ,
-+ 0x0100 , 0xfe00 , 0x0100 , 0xff00 ,
-+ 0x0700 , 0xfb00 , 0xfc00 , 0x0100 ,
-+ 0xfe00 , 0xfc00 , 0x0b00 , 0xfb00 ,
-+ 0xfb00 , 0x0700 , 0xfb00 , 0xfb00 ,
-+ 0x0100 , 0xff00 , 0xfb00 , 0xfd00 ,
-+ 0x0000 , 0xfe00 , 0xfe00 , 0xff00 ,
-+ 0xfc00 , 0x0400 , 0x0000 , 0xfe00 ,
-+ 0xff00 , 0x0200 , 0xff00 , 0x0000 ,
-+ 0x0500 , 0x0100 , 0x0100 , 0x0100 ,
-+ 0x0100 , 0x0000 , 0x0300 , 0xfe00 ,
-+ 0xff00 , 0x0100 , 0x0100 , 0xfe00 ,
-+ 0x0000 , 0xff00 , 0x0100 , 0xff00 ,
-+ 0x0200 , 0xff00 , 0xff00 , 0xff00 ,
-+ 0xff00 , 0xfe00 , 0x0000 , 0xff00 ,
-+ 0xfe00 , 0xff00 , 0xfd00 , 0x0000 ,
-+ 0xff00 , 0xfe00 , 0xff00 , 0xfc00 ,
-+ 0x0100 , 0xfd00 , 0xff00 , 0xff00 ,
-+ 0x0200 , 0xff00 , 0x0100 , 0xff00 ,
-+ 0xfc00 , 0x0300 , 0xff00 , 0x0200 ,
-+ 0xff00 , 0x0100 , 0xff00 , 0x0100 ,
-+ 0xff00 , 0xff00 , 0x0100 , 0xfe00 ,
-+ 0x0300 , 0xfc00 , 0x0100 , 0xff00 ,
-+ 0x0100 , 0x0100 , 0x0100 , 0xfc00 ,
-+ 0xff00 , 0x0100 , 0x0100 , 0xfe00 ,
-+ 0x0100 , 0xff00 , 0x0100 , 0xfc00 ,
-+ 0x0100 , 0x0200 , 0xff00 , 0x0100 ,
-+ 0xff00 , 0xff00 , 0x0200 , 0xfd00 ,
-+ 0xfe00 , 0x0100 , 0xff00 , 0x0100 ,
-+ 0xfe00 , 0x0100 , 0x0300 , 0xfe00 ,
-+ 0x0300 , 0xfe00 , 0xff00 , 0x0100 ,
-+ 0xff00 , 0x0200 , 0xfd00 , 0x0000 ,
-+ 0xff00 , 0x0200 , 0xff00 , 0x0200 ,
-+ 0xff00 , 0x0100 , 0x0000 , 0xff00 ,
-+ 0x0200 , 0x0100 , 0x0000 , 0xff00 ,
-+ 0x0100 , 0xfe00 , 0x0200 , 0xfe00 ,
-+ 0xfe00 , 0x0100 , 0xfe00 , 0x0100 ,
-+ 0xfd00 , 0xff00 , 0xff00 , 0xfe00 ,
-+ 0xff00 , 0xfc00 , 0x0100 , 0xfe00 ,
-+ 0x0100 , 0xff00 , 0xfe00 , 0xff00 ,
-+ 0xff00 , 0xfe00 , 0x0100 , 0xfe00 ,
-+ 0x0100 , 0xff00 , 0x0100 , 0xfe00 ,
-+ 0xff00 , 0x0200 , 0xfe00 , 0x0000 ,
-+ 0x0100 , 0x0200 , 0xff00 , 0x0200 ,
-+ 0xff00 , 0x0000 , 0x0100 , 0x0100 ,
-+ 0xff00 , 0x0200 , 0xfe00 , 0xff00 ,
-+ 0xff00 , 0xff00 , 0x0100 , 0x0000 ,
-+ 0xff00 , 0x0100 , 0xff00 , 0x0000 ,
-+ 0x0100 , 0xff00 , 0xfe00 , 0xff00 ,
-+ 0xff00 , 0x0100 , 0xff00 , 0x0100 ,
-+ 0xfe00 , 0xff00 , 0xff00 , 0xff00 ,
-+ 0xfe00 , 0xff00 , 0xff00 , 0x0100 ,
-+ 0xff00 , 0x0200 , 0xff00 , 0x0100 ,
-+ 0xff00 , 0xff00 };
-+
-+
-+unsigned short alarm_data[] = {
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
-+ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
-+
-+};
-+
-+
-+
-+
-+
-+#define SHARP_BUZ_TOUCHSOUND 1
-+#define SHARP_BUZ_KEYSOUND 2
-+#define SHARP_BUZ_ALARM 11
-+#define SHARP_BUZZER_MAKESOUND 0x5680
-+
-+static int collie_ct_s16_buzzer(const u_char *userPtr, size_t userCount,
-+ u_char frame[], ssize_t *frameUsed,
-+ ssize_t frameLeft)
-+{
-+ ssize_t count, used;
-+ signed short *fp = (unsigned short *) &frame[*frameUsed];
-+ signed short *up = (unsigned short *) userPtr;
-+
-+ DPRINTK("Collie_ct_s16 begin\n");
-+
-+ used = count = (userCount < frameLeft) ? userCount/2 : frameLeft/4;
-+
-+ DPRINTK("Collie_ct_s16 begin count %d \n",count);
-+
-+ while (count > 0) {
-+ *fp++ = *up;
-+ *fp++ = *up++;
-+ count--;
-+ }
-+
-+ *frameUsed+=used*4;
-+ DPRINTK("Collie_ct_s16 exit\n");
-+ return used*2;
-+}
-+
-+
-+static ssize_t sq_write_buzzer(int soundid)
-+{
-+ const char * src;
-+ audio_stream_t *s = &output_stream;
-+ u_char *dest;
-+ ssize_t uUsed, bUsed, bLeft, uLeft, ret = 0;
-+
-+
-+ if ((collie_tc_status!=NA) && (collie_tc_status!=PLAY))
-+ return -EPERM;
-+
-+ collie_tc_status=PLAY;
-+
-+ if (!s->buffers && sq_allocate_buffers(s)) {
-+ return -ENOMEM;
-+ }
-+
-+
-+#ifdef CONFIG_PM
-+ /* Auto Power off cancel */
-+// autoPowerCancel = 0;
-+#endif
-+ DPRINTK("sq_write_buzzer: id:%d\n", soundid);
-+
-+ switch (soundid) {
-+ case SHARP_BUZ_TOUCHSOUND:
-+ src=tap_data;
-+ uLeft=176*2;
-+ break;
-+ case SHARP_BUZ_KEYSOUND:
-+ src=click_data;
-+ uLeft=360*2;
-+ break;
-+ case SHARP_BUZ_ALARM:
-+ src=alarm_data;
-+ uLeft=3072*2;
-+ break;
-+ default:
-+ return 0;
-+ }
-+ DPRINTK("sq_write_buzzer: uLeft=%d\n", uLeft);
-+
-+ collie_tc_mute_off();
-+ while (uLeft > 0) {
-+ audio_buf_t *b = s->buf;
-+
-+ ret = -ERESTARTSYS;
-+ if (down_interruptible(&b->sem)) {
-+ break;
-+ }
-+
-+ dest = b->start + b->size;
-+ bUsed = 0;
-+ bLeft = s->fragsize - b->size;
-+ uUsed = collie_ct_s16_buzzer(src, uLeft, dest, &bUsed, bLeft);
-+ cpu_cache_clean_invalidate_range((unsigned long)dest,
-+ (unsigned long)(dest+(audio_fragsize)), 0);
-+
-+ DPRINTK("back to sq_write_buzzer %p\n",dest);
-+
-+ if (uUsed < 0) {
-+ up(&b->sem);
-+ return -EFAULT;
-+ }
-+ src += uUsed;
-+ uLeft -= uUsed;
-+ b->size += bUsed;
-+
-+ if (b->size < s->fragsize) {
-+ up(&b->sem);
-+ break;
-+ }
-+
-+ /* Send current buffer to dma */
-+ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
-+ (void *) b, b->dma_addr, b->size);
-+
-+ Collie_volume_set(4);
-+
-+ b->size = 0; /* indicate that the buffer has been sent */
-+ NEXT_BUF(s, buf);
-+ }
-+
-+ DPRINTK("sq_write_buzzer: return\n");
-+ return ret;
-+}
-+
-+
-+
-+
-+
-+
-+
-diff -Nuar linux-2.4.18/drivers/sound/collie_ssp.c linux-2.4.18p/drivers/sound/collie_ssp.c
---- linux-2.4.18/drivers/sound/collie_ssp.c 2003-05-13 11:18:37.000000000 +0200
-+++ linux-2.4.18p/drivers/sound/collie_ssp.c 2004-10-13 15:05:36.000000000 +0200
-@@ -9,6 +9,7 @@
- * I/F : Synchronous serial port (SSP) TI mode
- *
- * Copyright (C) 2001 SHARP
-+ * p.nis/dolOps messed around with it too!
- *
- * 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
-@@ -24,7 +25,18 @@
- * 23-Oct-2001 SHARP
- * tune hardware control method
- * 12-Nov-2001 Lineo Japan, Inc.
-- * 14-Feb-2003 Sharp Corporation 8bit , GETOSPACE
-+ *
-+ * 26-Dec-2002 getospace added, some unneeded things removed
-+ *
-+ * 28-Dec-2002 cut out old stuff, reorder stuff
-+ *
-+ * 04-Jan-2003 put in getospace from lineo's collie-tc35143.c
-+ * also added collie_record_on off, and exported these symbols
-+ *
-+ * 06-Jan-2003 if mixer ioctl SOUND_MIXER_READ_DEVMASK returns 0 as mask,
-+ * than the headphone(/mic) is not connected
-+ *
-+ *
- */
- #include <linux/module.h>
- #include <linux/sched.h>
-@@ -35,7 +47,7 @@
- #include <linux/fcntl.h>
- #include <linux/errno.h>
- #include <linux/mm.h>
--#include <linux/malloc.h>
-+#include <linux/slab.h>
- #include <linux/sound.h>
- #include <linux/init.h>
- #include <linux/delay.h>
-@@ -48,38 +60,30 @@
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/dma.h>
--#include <asm/ucb1200.h>
-
- #include <linux/soundcard.h>
- #include <asm/proc/cache.h>
-
--#include <asm/arch/gpio.h>
-+#include <asm/arch/hardware.h>
- #include <asm/arch/m62332.h>
- #include <asm/arch/tc35143.h>
-
- #undef DEBUG
--//#define DEBUG
- #ifdef DEBUG
- #define DPRINTK( x... ) printk( ##x )
- #else
- #define DPRINTK( x... )
- #endif
-
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
-- defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
--#define COLLIE_TRY_ONE
--#else
--#undef COLLIE_TRY_ONE
--#endif
-+#define COLLIE_TRY_ONE
-
- #ifdef COLLIE_TRY_ONE
- #ifndef GPIO_REMOCON_ADC_SW
- #define GPIO_REMOCON_ADC_SW GPIO_GPIO(18)
- #endif
-
-+static int collie_rc_irq;
- static DECLARE_WAIT_QUEUE_HEAD(audio_on);
--
--
- static inline void collie_rc_set_int_mode(void)
- {
- GPSR = GPIO_REMOCON_ADC_SW;
-@@ -91,14 +95,12 @@
- }
- #endif
-
--
- int collie_dmasound_irq = -1;
--#define COLLIE_SOUND_DMA_CHANNEL (collie_dmasound_irq)
-
-+#define COLLIE_SOUND_DMA_CHANNEL (collie_dmasound_irq)
- #define SND_NDEVS 256 /* Number of supported devices */
- #define SND_DEV_CTL 0 /* Control port /dev/mixer */
--#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
-- synthesizer and MIDI output) */
-+#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */
- #define SND_DEV_MIDIN 2 /* Raw midi access */
- #define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
- #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-@@ -121,142 +123,25 @@
- #endif
-
- /*** Some declarations ***********************************************/
--#define DMASND_TT 1
--#define DMASND_FALCON 2
--#define DMASND_AMIGA 3
--#define DMASND_AWACS 4
--#define DMASND_IRIS 5
--#define DMASND_COLLIE 6
-
--#define COLLIE_WAIT_AMP_ON 1 /* 10ms */
-+
- #define COLLIE_WAIT_LCM_ACC_XEN 50 /* 500ms */
--#ifdef MODULE
--static int catchRadius = 0;
--#endif
-+
- static int collie_amp_init = 0;
- static int collie_dac_init = 0;
--static int collie_op_shdn_on = 0;
- static int collie_resume = 0;
- static int collie_hard_mute = 1;
- static int collie_soft_mute = 1;
- static int collie_volume = 0;
-+int collie_recording=0;
-+static int playing=0;
-+static int headphone;
-
--int collie_buzzer_volume = 0;
--
--#if 1
--static DECLARE_WAIT_QUEUE_HEAD(open_queue);
-+#define AUDIO_NBFRAGS_DEFAULT 64
-+#define AUDIO_FRAGSIZE_DEFAULT 4096
-
--#define SIGNAL_RECEIVED (signal_pending(current))
--#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
--#define SLEEP(queue, time_limit) \
-- interruptible_sleep_on_timeout((wait_queue_head_t*)&queue, (time_limit));
--#define WAKE_UP(queue) (wake_up_interruptible((wait_queue_head_t*)&queue))
--#endif
--
--#define AUDIO_NBFRAGS_DEFAULT 8
--#define AUDIO_FRAGSIZE_DEFAULT 8192
--
--
--#define TRACE 0
--#if TRACE
--#define TRACE_ON 1
--#define TRACE_SEM 0
--#define TRACE_SENDDATA 0
--#define TRACE_PM 1
--#define TRACE_AMP 1
--#define TRACE_DAC 1
--#define TRACE_OP_SHDN 1
--#define TRACE_WRITE 1
--#define TRACE_MUTE 1
--#define TRACE_CLOCK 1
--#define TRACE_PAIF 1
--#define TRACE_SSP 1
--#define TRACE_VOLUME 1
--#define TRACE_MIC 1
--#define TRACE_INTERRUPT 0
--int cLevel = 0;
--char *pLevel[16] = {
-- /* 0 */"",
-- /* 1 */" ",
-- /* 2 */" ",
-- /* 3 */" ",
-- /* 4 */" ",
-- /* 5 */" ",
-- /* 6 */" ",
-- /* 7 */" ",
-- /* 8 */" ",
-- /* 9 */" ",
-- /* 10 */" ",
-- /* 11 */" ",
-- /* 12 */" ",
-- /* 13 */" ",
-- /* 14 */" ",
-- /* 15 */" "
--};
--char *
--indent(int level)
--{
-- int i;
-- return (level < 16 ) ? pLevel[level] : pLevel[15];
--}
--
--#define P_ID (current->tgid)
--#define ENTER(f,fn) {if(f)printk("%d:%s+[%d]%s\n",jiffies,indent(cLevel),P_ID,(fn));cLevel++;}
--#define LEAVE(f,fn) {cLevel--;if(f>1)printk("%d:%s-[%d]%s\n",jiffies,indent(cLevel),P_ID,(fn));}
--#else /* ! TRACE */
--#define ENTER(f,fn)
--#define LEAVE(f,fn)
--#endif /* end TRACE */
-
--/*
-- * DAC power management
-- */
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
-- defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
--#define DAC_OFF_WITH_DEVICE_OFF 1
--#undef HARD_MUTE_CTRL_DISABLE
--#else
--#undef DAC_OFF_WITH_DEVICE_OFF
- #undef HARD_MUTE_CTRL_DISABLE
--#endif
--
--
--#define TRY_DELAY_OFF
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */
--static DECLARE_WAIT_QUEUE_HEAD(delay_off);
--struct semaphore df_sem;
--/*
-- * delay execution
-- */
--static unsigned int DelayedFlag = 0;
--#define DELAY_DAC_OFF 0x1
--#define DELAY_HARD_MUTE_ON 0x2
--
--static inline void ResetDelayAll(void)
--{
-- DelayedFlag = 0;
--}
--
--static inline int isDelayedExist(void)
--{
-- return DelayedFlag;
--}
--
--static inline void SetDelay(unsigned int flag)
--{
-- DelayedFlag |= flag;
--}
--
--static inline void ResetDelay(unsigned int flag)
--{
-- DelayedFlag &= ~flag;
--}
--
--static inline unsigned int isDelayed(unsigned int flag)
--{
-- return DelayedFlag & flag;
--}
--#endif
-
- /*
- * Buffer Management
-@@ -268,6 +153,7 @@
- dma_addr_t dma_addr; /* physical buffer address */
- struct semaphore sem; /* down before touching the buffer */
- int master; /* master owner for buffer allocation */
-+ u_int idx; /* buffer index, so that we know which buffer was sent last*/
- } audio_buf_t;
-
- typedef struct {
-@@ -291,16 +177,6 @@
-
- static volatile int audio_wr_refcount; /* nbr of concurrent open() for playback */
-
--static ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
--
--#ifdef MODULE
--MODULE_PARM(catchRadius, "i");
--#endif
--MODULE_PARM(numBufs, "i");
--MODULE_PARM(bufSize, "i");
--
--#define min(x, y) ((x) < (y) ? (x) : (y))
--
- #define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
-@@ -310,11 +186,7 @@
- /*
- * SA1110 GPIO (17)
- */
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
--#define COLLIE_GPIO_OPSHDN GPIO_GPIO (17) /* AMP contorol */
--#else /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
- #define COLLIE_GPIO_MIC GPIO_GPIO (17) /* MIC contorol */
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
-
- /*
- * DAC setup data
-@@ -352,122 +224,11 @@
- ( LCM_ACC_XSEL1 | LCM_ACC_CLKSEL101 ) ,
- };
-
-+/*** "Translations" ************************************************************/
-
--/* 16 bit mu-law */
--
--static short ulaw2dma16[] = {
-- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
-- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-- -876, -844, -812, -780, -748, -716, -684, -652,
-- -620, -588, -556, -524, -492, -460, -428, -396,
-- -372, -356, -340, -324, -308, -292, -276, -260,
-- -244, -228, -212, -196, -180, -164, -148, -132,
-- -120, -112, -104, -96, -88, -80, -72, -64,
-- -56, -48, -40, -32, -24, -16, -8, 0,
-- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
-- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
-- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
-- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
-- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
-- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
-- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
-- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
-- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
-- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
-- 876, 844, 812, 780, 748, 716, 684, 652,
-- 620, 588, 556, 524, 492, 460, 428, 396,
-- 372, 356, 340, 324, 308, 292, 276, 260,
-- 244, 228, 212, 196, 180, 164, 148, 132,
-- 120, 112, 104, 96, 88, 80, 72, 64,
-- 56, 48, 40, 32, 24, 16, 8, 0,
--};
--
--/* 16 bit A-law */
--
--static short alaw2dma16[] = {
-- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
-- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-- -344, -328, -376, -360, -280, -264, -312, -296,
-- -472, -456, -504, -488, -408, -392, -440, -424,
-- -88, -72, -120, -104, -24, -8, -56, -40,
-- -216, -200, -248, -232, -152, -136, -184, -168,
-- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-- -688, -656, -752, -720, -560, -528, -624, -592,
-- -944, -912, -1008, -976, -816, -784, -880, -848,
-- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
-- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
-- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
-- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
-- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
-- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
-- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
-- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
-- 344, 328, 376, 360, 280, 264, 312, 296,
-- 472, 456, 504, 488, 408, 392, 440, 424,
-- 88, 72, 120, 104, 24, 8, 56, 40,
-- 216, 200, 248, 232, 152, 136, 184, 168,
-- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
-- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
-- 688, 656, 752, 720, 560, 528, 624, 592,
-- 944, 912, 1008, 976, 816, 784, 880, 848,
--};
--
--
--
--/*** Translations ************************************************************/
--
--static ssize_t collie_ct_law(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft);
--static ssize_t collie_ct_s8(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft);
--static ssize_t collie_ct_u8(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft);
- static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
--static ssize_t collie_ct_u16(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft);
--
--/*** Machine definitions *****************************************************/
--
--
--typedef struct {
-- int type;
-- void *(*dma_alloc)(unsigned int, int);
-- void (*dma_free)(void *, unsigned int);
-- int (*irqinit)(void);
--#ifdef MODULE
-- void (*irqcleanup)(void);
--#endif /* MODULE */
-- void (*init)(void);
-- void (*silence)(void);
-- int (*setFormat)(int);
-- int (*setVolume)(int);
-- int (*setBass)(int);
-- int (*setTreble)(int);
-- int (*setGain)(int);
-- void (*play)(void);
--} MACHINE;
--
-
- /*** Low level stuff *********************************************************/
-
-@@ -477,71 +238,28 @@
- int stereo; /* 0 = mono, 1 = stereo */
- int size; /* 8/16 bit*/
- int speed; /* speed */
-+ int volume;
- } SETTINGS;
-
--typedef struct {
-- ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-- ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
--} TRANS;
--
--struct sound_settings {
-- MACHINE mach; /* machine dependent things */
-- SETTINGS hard; /* hardware settings */
-- SETTINGS soft; /* software settings */
-- SETTINGS dsp; /* /dev/dsp default settings */
-- TRANS *trans; /* supported translations */
-- int volume_left; /* volume (range is machine dependent) */
-- int volume_right;
-- int bass; /* tone (range is machine dependent) */
-- int treble;
-- int gain;
-- int minDev; /* minor device number currently open */
--};
--
--static struct sound_settings sound;
-+static SETTINGS sound;
-
- #ifdef CONFIG_PM
--extern int autoPowerCancel;
-+//extern int autoPowerCancel;
- #endif
--int collie_main_volume;
--extern int collie_under_recording; /* collie_buzzer.c */
--#define COLLE_RECORDING (collie_under_recording)
-
- static void Collie_Set_Volume(int volume);
- static int Collie_Get_Volume(void);
--static void Collie_disable_sound(void);
--#ifdef CONFIG_PM
--#if 0
--static void Collie_clock_stop(void);
--static void Collie_FS8KLPF_stop(void);
--#endif
--#endif
- static int CollieIrqInit(void);
- static int CollieGetSamp(void);
--static void Collie_OP_SHDN_on(void);
--static void Collie_OP_SHDN_off(void);
--static void Collie_FS8KLPF_start(void);
--#ifdef MODULE
--static void CollieIrqCleanUp(void);
--#endif /* MODULE */
--static void CollieSilence(void);
- static void Collie_DAC_sendword(int);
--static void CollieInit(void);
- static int CollieSetFormat(int format);
- static void Collie_sq_interrupt(void*, int);
- static int sq_allocate_buffers(audio_stream_t*);
- static void sq_release_buffers(audio_stream_t*);
-+static inline void Collie_volume_init(void);
-+static void Collie_volume_set(int);
-
- /*** Mid level stuff *********************************************************/
--static void sound_silence(void);
--static void sound_init(void);
--static int sound_set_format(int format);
- static int sound_set_speed(int speed);
- static int sound_set_stereo(int stereo);
-
-@@ -572,468 +290,122 @@
- static long long sound_lseek(struct file *file, long long offset, int orig);
- static inline int ioctl_return(int *addr, int value)
- {
-- ENTER(TRACE_ON,"ioctl_return");
- if (value < 0) {
-- LEAVE(TRACE_ON,"ioctl_return");
- return(value);
- }
--
-- LEAVE(TRACE_ON,"ioctl_return");
- return put_user(value, addr)? -EFAULT: 0;
- }
-
--
--/*** Config & Setup **********************************************************/
--
--
--void dmasound_init(void);
--void dmasound_setup(char *str, int *ints);
--
--
--/*** Translations ************************************************************/
--
--
--/* ++TeSche: radically changed for new expanding purposes...
-- *
-- * These two routines now deal with copying/expanding/translating the samples
-- * from user space into our buffer at the right frequency. They take care about
-- * how much data there's actually to read, how much buffer space there is and
-- * to convert samples into the right frequency/encoding. They will only work on
-- * complete samples so it may happen they leave some bytes in the input stream
-- * if the user didn't write a multiple of the current sample size. They both
-- * return the number of bytes they've used from both streams so you may detect
-- * such a situation. Luckily all programs should be able to cope with that.
-- *
-- * I think I've optimized anything as far as one can do in plain C, all
-- * variables should fit in registers and the loops are really short. There's
-- * one loop for every possible situation. Writing a more generalized and thus
-- * parameterized loop would only produce slower code. Feel free to optimize
-- * this in assembler if you like. :)
-- *
-- * I think these routines belong here because they're not yet really hardware
-- * independent, especially the fact that the Falcon can play 16bit samples
-- * only in stereo is hardcoded in both of them!
-- *
-- * ++geert: split in even more functions (one per format)
-- */
--
--static ssize_t collie_ct_law(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft)
--{
-- short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
-- ssize_t count, used;
-- short *p = (short *) &frame[*frameUsed];
-- int val, stereo = sound.soft.stereo;
--
-- ENTER(TRACE_ON,"collie_ct_law");
-- frameLeft >>= 2;
-- if (stereo)
-- userCount >>= 1;
-- used = count = min(userCount, frameLeft);
-- if (!COLLE_RECORDING) {
-- while (count > 0) {
-- u_char data;
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_law");
-- return -EFAULT;
-- }
-- val = table[data];
-- *p++ = val; /* Left Ch. */
-- if (stereo) {
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_law");
-- return -EFAULT;
-- }
-- val = table[data];
-- }
-- *p++ = val; /* Right Ch. */
-- count--;
-- }
-- } else {
-- while (count > 0) {
-- u_char data;
-- int ave;
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_law");
-- return -EFAULT;
-- }
-- val = table[data];
-- ave = val; /* Left Ch. */
-- if (stereo) {
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_law");
-- return -EFAULT;
-- }
-- val = table[data];
-- }
-- ave += val; /* Right Ch. */
-- ave >>= 1;
-- *p++ = 0; /* Left Ch. */
-- *p++ = ave; /* Right Ch. */
-- count--;
-- }
-- }
-- *frameUsed += used * 4;
-- LEAVE(TRACE_ON,"collie_ct_law");
-- return stereo? used * 2: used;
--}
--
--
--static ssize_t collie_ct_s8(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft)
--{
-- ssize_t count, used;
-- short *p = (short *) &frame[*frameUsed];
-- int stereo = sound.soft.stereo;
-- short val;
--
-- ENTER(TRACE_ON,"collie_ct_s8");
-- frameLeft >>= 2;
-- if (stereo)
-- userCount >>= 1;
-- used = count = min(userCount, frameLeft);
-- if (!COLLE_RECORDING) {
-- while (count > 0) {
-- u_char data;
--
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_s8");
-- return -EFAULT;
-- }
-- val = ( data - 0x80 ) << 8;
-- *p++ = val; /* Left Ch. */
-- if ( stereo ) {
-- if ( get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_s8");
-- return -EFAULT;
-- }
-- val = ( data - 0x80 ) << 8;
-- }
-- *p++ = val; /* Right Ch. */
-- count--;
-- }
-- } else {
-- while (count > 0) {
-- u_char data;
-- int ave;
--
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_s8");
-- return -EFAULT;
-- }
-- val = ( data - 0x80 ) << 8;
-- ave = val; /* Left Ch. */
-- if ( stereo ) {
-- if ( get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_s8");
-- return -EFAULT;
-- }
-- val = ( data - 0x80 ) << 8;
-- }
-- ave += val; /* Right Ch. */
-- ave >>= 1;
-- *p++ = 0; /* Left Ch. */
-- *p++ = ave; /* Right Ch. */
-- count--;
-- }
-- }
-- *frameUsed += used * 4;
-- LEAVE(TRACE_ON,"collie_ct_s8");
-- return stereo? used * 2: used;
--}
--
--
--static ssize_t collie_ct_u8(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft)
-+static void wait_ms(int ten_ms)
- {
-- ssize_t count, used;
-- short *p = (short *) &frame[*frameUsed];
-- int stereo = sound.soft.stereo;
-- short val;
--
-- ENTER(TRACE_ON,"collie_ct_u8");
-- frameLeft >>= 2;
-- if (stereo)
-- userCount >>= 1;
-- used = count = min(userCount, frameLeft);
-- if (!COLLE_RECORDING) {
-- while (count > 0) {
-- u_char data;
--
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_u8");
-- return -EFAULT;
-- }
-- val = data;
-- *p++ = (val ^ 0x80) << 8; /* Left Ch. */
-- if ( stereo ) {
-- if ( get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_u8");
-- return -EFAULT;
-- }
-- val = data;
-- }
-- *p++ = (val ^ 0x80) << 8; /* Right Ch. */
-- count--;
-- }
-- } else {
-- while (count > 0) {
-- u_char data;
-- int ave;
--
-- if (get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_u8");
-- return -EFAULT;
-- }
-- val = data;
-- ave = (val ^ 0x80) << 8; /* Left Ch. */
-- if ( stereo ) {
-- if ( get_user(data, userPtr++)) {
-- LEAVE(TRACE_ON,"collie_ct_u8");
-- return -EFAULT;
-- }
-- val = data;
-- }
-- ave += (val ^ 0x80) << 8; /* Right Ch. */
-- ave >>= 1;
-- *p++ = 0; /* Left Ch. */
-- *p++ = ave; /* Right Ch. */
-- count--;
-- }
-- }
-- *frameUsed += used * 4;
-- LEAVE(TRACE_ON,"collie_ct_u8");
-- return stereo? used * 2: used;
-+ schedule_timeout(ten_ms);
- }
-
-+/*** Translation ************************************************************/
-
- static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
- {
- ssize_t count, used;
-- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-+ short *up = (short *) userPtr;
-
-- ENTER(TRACE_ON,"collie_ct_s16");
- frameLeft >>= 2;
-- userCount >>= (stereo? 2: 1);
-- used = count = min(userCount, frameLeft);
-- if (!stereo) {
-- short *up = (short *) userPtr;
-- while (count > 0) {
-- short data;
-- if (get_user(data, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_s16");
-- return -EFAULT;
-- }
-- *fp++ = (!COLLE_RECORDING) ? data : 0; /* Left Ch. */
-- *fp++ = data;
-- count--;
-+ userCount >>= 2;
-+ used = count = (userCount < frameLeft) ? userCount : frameLeft;
-+
-+ while (count > 0) {
-+
-+ short data;
-+ if (get_user(data, up++)) {
-+ return -EFAULT;
- }
-- } else {
-- short *up = (short *) userPtr;
-- while (count > 0) {
-- short data;
-- short temp;
-- if (get_user(data, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_s16");
-- return -EFAULT;
-- }
-- if (get_user(temp, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_s16");
-- return -EFAULT;
-- }
-- if (!COLLE_RECORDING) {
-- *fp++ = data; /* Left Ch. */
-- *fp++ = temp; /* Right Ch. */
-- } else {
-- data >>= 1;
-- data += (temp >> 1);
-- *fp++ = 0; /* Left Ch. */
-- *fp++ = data; /* Right Ch. */
-- }
-- count--;
-+ if (!collie_recording) *fp++ = data;
-+ else *fp++=0;
-+
-+ if (get_user(data, up++)) {
-+ return -EFAULT;
- }
-+ *fp++ = data;
-+ count--;
- }
-+
- *frameUsed += used * 4;
-- LEAVE(TRACE_ON,"collie_ct_s16");
-- return stereo? used * 4: used * 2;
-+ return used * 4;
- }
-
--static ssize_t collie_ct_u16(const u_char *userPtr, size_t userCount,
-- u_char frame[], ssize_t *frameUsed,
-- ssize_t frameLeft)
--{
-- ssize_t count, used;
-- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-- int stereo = sound.soft.stereo;
-- short *fp = (short *) &frame[*frameUsed];
-- short *up = (short *) userPtr;
-+/*** HARDWARE dependent stuff *********************************************************/
-
-- ENTER(TRACE_ON,"collie_ct_u16");
-- frameLeft >>= 2;
-- userCount >>= (stereo? 2: 1);
-- used = count = min(userCount, frameLeft);
-- if (!COLLE_RECORDING) {
-- while (count > 0) {
-- int data;
-- int temp;
-- if (get_user(data, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_u16");
-- return -EFAULT;
-- }
-- data ^= mask;
-- *fp++ = data; /* Left Ch. */
-- if (stereo) {
-- if (get_user(temp, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_u16");
-- return -EFAULT;
-- }
-- temp ^= mask;
-- data = temp;
-- data ^= mask;
-- }
-- *fp++ = data; /* Right Ch. */
-- count--;
-- }
-+static inline void Collie_DAC_sendbit(int bit_data)
-+{
-+ if (bit_data & 1) {
-+ LCM_GPO |= (LCM_GPIO_DAC_SDATA);
- } else {
-- while (count > 0) {
-- int data;
-- int temp;
-- int ave;
-- if (get_user(data, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_u16");
-- return -EFAULT;
-- }
-- data ^= mask;
-- ave = data; /* Left Ch. */
-- if (stereo) {
-- if (get_user(temp, up++)) {
-- LEAVE(TRACE_ON,"collie_ct_u16");
-- return -EFAULT;
-- }
-- temp ^= mask;
-- data = temp;
-- data ^= mask;
-- }
-- ave += data;
-- ave >>= 1;
-- *fp++ = 0; /* Left Ch. */
-- *fp++ = ave; /* Right Ch. */
-- count--;
-- }
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
- }
-- *frameUsed += used * 4;
-- LEAVE(TRACE_ON,"collie_ct_u16");
-- return stereo? used * 4: used * 2;
--}
-
--static TRANS transCollie = {
-- collie_ct_law, collie_ct_law, collie_ct_s8, collie_ct_u8,
-- collie_ct_s16, collie_ct_u16, collie_ct_s16, collie_ct_u16
--};
-+ udelay(1);
-+ LCM_GPO |= (LCM_GPIO_DAC_SCK);
-
--/*** Low level stuff *********************************************************/
-+ udelay(1);
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
-+ udelay(1);
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
-+ udelay(1);
-+}
-
--static void Collie_Set_Volume(int volume)
-+static void Collie_DAC_sendword(int data)
- {
-- ENTER(TRACE_ON,"Collie_Set_Volume");
--
-- sound.volume_left = volume & 0xff;
-- if ( sound.volume_left > 100 ) sound.volume_left = 100;
--
-- collie_main_volume = sound.volume_left;
--
-- sound.volume_right = ( volume & 0xff00 >> 8);
-- if ( sound.volume_right > 100 ) sound.volume_right = 100;
-- LEAVE(TRACE_ON,"Collie_Set_Volume");
-+ int i;
-
-- collie_buzzer_volume = sound.volume_right;
-+#if defined(CONFIG_COLLIE_PCM1741)
-+
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
-+ udelay(1);
-+ LCM_GPO |= (LCM_GPIO_DAC_SLOAD);
-+ udelay(1);
-
--}
-+ for (i = 0; i < 16; i++)
-+ Collie_DAC_sendbit(data >> (15 - i));
-
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-+ udelay(2);
-
--static int Collie_Get_Volume(void)
--{
-- ENTER(TRACE_ON,"Collie_Get_Volume");
-- LEAVE(TRACE_ON,"Collie_Get_Volume");
-- return ( sound.volume_right << 8 | sound.volume_left );
--}
-+#elif defined(CONFIG_COLLIE_PCM1717)
-+
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-+ udelay(1000);
-+ LCM_GPO |= (LCM_GPIO_DAC_SLOAD);
-+ udelay(1000);
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
-+ udelay(1000);
-
--static void wait_ms(int ten_ms)
--{
-- ENTER(TRACE_ON,"wait_ms");
-- LEAVE(TRACE_ON,"wait_ms");
-- schedule_timeout(ten_ms);
--}
-+ for (i = 0; i < 16; i++)
-+ Collie_DAC_sendbit(data >> (15 - i));
-
--static inline void Collie_AMP_off(void)
--{
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_AMP,"Collie_AMP_off");
--#if 0 /* OBSOLETED: power controled by only OP_SHDN */
-- /* Set up TC35143 GPIO I/O Direction (GPIO4 output mode) */
-- ucb1200_set_io_direction(TC35143_GPIO_AMP_ON,
-- TC35143_IODIR_OUTPUT);
-- /* AMP OFF */
-- ucb1200_set_io(TC35143_GPIO_AMP_ON,
-- TC35143_IODAT_LOW);
-- collie_amp_init = 0;
--#endif /* 0 */
-- LEAVE(TRACE_AMP,"Collie_AMP_off");
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
--}
--
--static inline void Collie_AMP_on(void)
--{
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_AMP,"Collie_AMP_on");
--// if (!collie_amp_init) {
-- /* Set up TC35143 GPIO I/O Direction (GPIO4 output mode) */
-- ucb1200_set_io_direction(TC35143_GPIO_AMP_ON,
-- TC35143_IODIR_OUTPUT);
-- /* AMP ON */
-- ucb1200_set_io(TC35143_GPIO_AMP_ON, TC35143_IODAT_HIGH);
-- SCP_REG_GPWR |= SCP_AMP_ON;
-- wait_ms(COLLIE_WAIT_AMP_ON);
-- collie_amp_init = 1;
--// }
-- LEAVE(TRACE_AMP,"Collie_AMP_on");
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-+ udelay(1000);
-+ LCM_GPO |= (LCM_GPIO_DAC_SLOAD);
-+ udelay(1000);
-+ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-+ udelay(1000);
-+#endif
- }
-
--static inline void Collie_AMP_init(void)
--{
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_AMP,"Collie_AMP_init");
-- Collie_AMP_off();
-- LEAVE(TRACE_AMP,"Collie_AMP_init");
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
--}
-
- static inline void Collie_DAC_off(void)
- {
-- ENTER(TRACE_DAC,"Collie_DAC_off");
-- if (!COLLE_RECORDING) {
-- /* DAC OFF */
-- LCM_GPD &= ~(LCM_GPIO_DAC_ON); /* set up output */
-- LCM_GPO &= ~(LCM_GPIO_DAC_ON);
--
-- /* LoCoMo GPIO disable */
-- LCM_GPE &= ~(LCM_GPIO_DAC_ON);
-- collie_dac_init = 0;
-- }
-- LEAVE(TRACE_DAC,"Collie_DAC_off");
-+ /* DAC OFF */
-+ LCM_GPD &= ~(LCM_GPIO_DAC_ON); /* set up output */
-+ LCM_GPO &= ~(LCM_GPIO_DAC_ON);
-+ /* LoCoMo GPIO disable */
-+ LCM_GPE &= ~(LCM_GPIO_DAC_ON);
-+ collie_dac_init = 0;
- }
-
- static inline void Collie_DAC_on(void)
- {
-- ENTER(TRACE_DAC,"Collie_DAC_on");
--// if (!collie_dac_init) {
- if (!(LCM_GPO & LCM_GPIO_DAC_ON)) {
- /* LoCoMo GPIO enable */
- LCM_GPE &= ~LCM_GPIO_DAC_ON;
-@@ -1049,24 +421,10 @@
- schedule();
- }
- }
--// }
-- LEAVE(TRACE_DAC,"Collie_DAC_on");
--}
--
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP */
--static inline void Collie_DAC_delay_off(void)
--{
-- ENTER(TRACE_DAC,"Collie_DAC_deleay_off");
-- down(&df_sem);
-- SetDelay(DELAY_DAC_OFF);
-- up(&df_sem);
-- LEAVE(TRACE_DAC,"Collie_DAC_delay_off");
- }
--#endif
-
- static inline void Collie_DAC_init(void)
- {
-- ENTER(TRACE_DAC,"Collie_DAC_init");
- /* LoCoMo GPIO enable */
- LCM_GPE &=
- ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD);
-@@ -1075,7 +433,6 @@
- ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD);
-
- #if defined(CONFIG_COLLIE_PCM1741)
--
- Collie_DAC_sendword(DAC_REG16_SetupData); /* register16 */
- Collie_DAC_sendword(DAC_REG17_SetupData); /* register17 */
- Collie_DAC_sendword(DAC_REG18_SetupData); /* register18 */
-@@ -1083,78 +440,53 @@
- Collie_DAC_sendword(DAC_REG20_SetupData); /* register20 */
- //// Collie_DAC_sendword(DAC_REG21_SetupData); /* register21 */
- Collie_DAC_sendword(DAC_REG22_SetupData); /* register22 */
--
- #elif defined(CONFIG_COLLIE_PCM1717)
--
- Collie_DAC_sendword(DAC_MODE0_SetupData); /* MODE0 */
- Collie_DAC_sendword(DAC_MODE1_SetupData); /* MODE1 */
- Collie_DAC_sendword(DAC_MODE2_SetupData); /* MODE2 */
- Collie_DAC_sendword(DAC_MODE3_SetupData); /* MODE3 */
--
- #endif
--
- /* LoCoMo GPIO disable */
- LCM_GPE &=
- ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD);
-- LEAVE(TRACE_DAC,"Collie_DAC_init");
- }
-
- static inline void Collie_soft_DAC_on(void)
- {
- #if defined(CONFIG_COLLIE_PCM1741)
-- ENTER(TRACE_DAC, "Collie_soft_DAC_on");
- Collie_DAC_sendword(DAC_REG19_DACOn); /* register19 */
-- LEAVE(TRACE_DAC, "Collie_soft_DAC_on");
- #endif /* CONFIG_COLLIE_PCM1741 */
- }
-
- static inline void Collie_soft_DAC_off(void)
- {
- #if defined(CONFIG_COLLIE_PCM1741)
-- ENTER(TRACE_DAC, "Collie_soft_DAC_off");
- Collie_DAC_sendword(DAC_REG19_DACOff); /* register19 */
-- LEAVE(TRACE_DAC, "Collie_soft_DAC_off");
--#endif /* CONFIG_COLLIE_PCM1741 */
--}
--
--static inline void Collie_soft_mute_init(void)
--{
--#if defined(CONFIG_COLLIE_PCM1741)
-- ENTER(TRACE_MUTE, "Collie_soft_mute_init");
-- Collie_DAC_sendword(DAC_REG18_MuteOn); /* register18 */
-- collie_soft_mute = 1;
-- LEAVE(TRACE_MUTE, "Collie_soft_mute_init");
- #endif /* CONFIG_COLLIE_PCM1741 */
- }
-
- static inline void Collie_soft_mute_on(void)
- {
- #if defined(CONFIG_COLLIE_PCM1741)
-- ENTER(TRACE_MUTE, "Collie_soft_mute_on");
- if (!collie_soft_mute) {
- Collie_DAC_sendword(DAC_REG18_MuteOn); /* register18 */
- collie_soft_mute = 1;
- }
-- LEAVE(TRACE_MUTE, "Collie_soft_mute_on");
- #endif /* CONFIG_COLLIE_PCM1741 */
- }
-
- static inline void Collie_soft_mute_off(void)
- {
- #if defined(CONFIG_COLLIE_PCM1741)
-- ENTER(TRACE_MUTE, "Collie_soft_mute_off");
- if (collie_soft_mute) {
- Collie_DAC_sendword(DAC_REG18_MuteOff); /* register18 */
- collie_soft_mute = 0;
- }
-- LEAVE(TRACE_MUTE, "Collie_soft_mute_off");
- #endif /* CONFIG_COLLIE_PCM1741 */
- }
-
- static inline void Collie_hard_mute_init(void)
- {
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_MUTE, "Collie_hard_mute_init");
- SCP_REG_GPCR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15);
- #ifdef HARD_MUTE_CTRL_DISABLE
- SCP_REG_GPWR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15);
-@@ -1162,84 +494,107 @@
- SCP_REG_GPWR &= ~(SCP_GPCR_PA14 | SCP_GPCR_PA15);
- #endif /* HARD_MUTE_CTRL_DISABLE */
- collie_hard_mute = 1;
--#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
-+
- {
- int time = jiffies + 5;
- while (jiffies <= time)
- schedule();
- }
--#endif
-- LEAVE(TRACE_MUTE, "Collie_hard_mute_init");
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
- }
-
- static inline void Collie_hard_mute_on(void)
- {
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
- #ifndef HARD_MUTE_CTRL_DISABLE
-- ENTER(TRACE_MUTE, "Collie_hard_mute_on");
- if (!collie_hard_mute) {
- SCP_REG_GPWR &= ~(SCP_GPCR_PA14 | SCP_GPCR_PA15);
- collie_hard_mute = 1;
--#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
- {
- int time = jiffies + 5;
- while (jiffies <= time)
- schedule();
- }
--#endif
- }
-- LEAVE(TRACE_MUTE, "Collie_hard_mute_on");
- #endif /* HARD_MUTE_CTRL_DISABLE */
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
- }
-
- static inline void Collie_hard_mute_off(void)
- {
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
- #ifndef HARD_MUTE_CTRL_DISABLE
-- ENTER(TRACE_MUTE, "Collie_hard_mute_off");
- if (collie_hard_mute) {
-- if (!COLLE_RECORDING)
- SCP_REG_GPWR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15);
-- else
-- SCP_REG_GPWR |= (SCP_GPCR_PA15);
- collie_hard_mute = 0;
--#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
- {
- int i;
- for (i=0; i<=1000; i++) {
- udelay(1);
- }
- }
--#endif
- }
-- LEAVE(TRACE_MUTE, "Collie_hard_mute_off");
- #endif /* HARD_MUTE_CTRL_DISABLE */
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
--}
--
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */
--static inline void Collie_hard_mute_delay_on(void)
--{
-- ENTER(TRACE_MUTE, "Collie_hard_mute_delay_on");
-- down(&df_sem);
-- SetDelay(DELAY_HARD_MUTE_ON);
-- up(&df_sem);
-- LEAVE(TRACE_MUTE, "Collie_hard_mute_delay_on");
- }
--#endif
-
--static inline void Collie_audio_clock_init(void)
-+static inline void Collie_hard_mute_left_on(void)
-+{
-+#ifndef HARD_MUTE_CTRL_DISABLE
-+// if (!collie_hard_mute) {
-+ SCP_REG_GPWR &= ~(SCP_GPCR_PA14);
-+ {
-+ int time = jiffies + 5;
-+ while (jiffies <= time)
-+ schedule();
-+ }
-+// }
-+#endif /* HARD_MUTE_CTRL_DISABLE */
-+}
-+
-+static inline void Collie_hard_mute_left_off(void)
-+{
-+#ifndef HARD_MUTE_CTRL_DISABLE
-+// if (collie_hard_mute) {
-+ SCP_REG_GPWR |= (SCP_GPCR_PA14);
-+ {
-+ int i;
-+ for (i=0; i<=1000; i++) {
-+ udelay(1);
-+ }
-+ }
-+// }
-+#endif /* HARD_MUTE_CTRL_DISABLE */
-+}
-+
-+
-+static int CollieGetSamp(void)
-+{
-+ switch (sound.speed) {
-+ case 8000:
-+ return clock_set_data[7];
-+ case 44100:
-+ return clock_set_data[0];
-+ case 22050:
-+ return clock_set_data[1];
-+ case 11025:
-+ return clock_set_data[2];
-+ case 48000:
-+ return clock_set_data[3];
-+ case 32000:
-+ return clock_set_data[4];
-+ case 24000:
-+ return clock_set_data[5];
-+ case 16000:
-+ return clock_set_data[6];
-+ default:
-+ printk("Collie sound: Illegal sound rate %d\n", sound.speed);
-+ return clock_set_data[7];
-+ }
-+}
-+
-+static inline void Collie_audio_clock_init(void)
- {
-- ENTER(TRACE_CLOCK, "Collie_audio_clock_init");
- LCM_ACC = 0;
-- LEAVE(TRACE_CLOCK, "Collie_audio_clock_init");
- }
-
- static inline void Collie_audio_clock_on(void)
- {
-- ENTER(TRACE_CLOCK, "Collie_audio_clock_on");
- /* LoCoMo Audio clock on */
- LCM_ACC = CollieGetSamp();
- barrier();
-@@ -1248,263 +603,58 @@
- LCM_ACC |= LCM_ACC_XEN;
- barrier();
- LCM_ACC |= (LCM_ACC_MCLKEN | LCM_ACC_64FSEN);
-- LEAVE(TRACE_CLOCK, "Collie_audio_clock_on");
- }
-
- static inline void Collie_audio_clock_off(void)
- {
-- ENTER(TRACE_CLOCK, "Collie_audio_clock_off");
- /* LoCoMo Audio clock off */
- LCM_ACC &= ~(LCM_ACC_XEN | LCM_ACC_MCLKEN | LCM_ACC_64FSEN);
- barrier();
- LCM_ACC &= ~(LCM_ACC_XON);
-- LEAVE(TRACE_CLOCK, "Collie_audio_clock_off");
--}
--
--static inline void Collie_paif_init(void)
--{
-- ENTER(TRACE_PAIF, "Collie_paif_init");
-- // LCM_PAIF = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST);
-- LCM_PAIF = (LCM_PAIF_LRCRST);
-- LEAVE(TRACE_PAIF, "Collie_paif_init");
- }
-
- static inline void Collie_paif_on(void)
- {
-- ENTER(TRACE_PAIF, "Collie_paif_on");
- LCM_PAIF = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST);
- LCM_PAIF &= ~(LCM_PAIF_LRCRST);
- LCM_PAIF |= (LCM_PAIF_SCEN | LCM_PAIF_LRCEN);
-- LEAVE(TRACE_PAIF, "Collie_paif_on");
- }
-
- static inline void Collie_paif_off(void)
- {
-- ENTER(TRACE_PAIF, "Collie_paif_off");
-- // LCM_PAIF = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST);
- LCM_PAIF = (LCM_PAIF_LRCRST);
-- LEAVE(TRACE_PAIF, "Collie_paif_off");
- }
-
- static inline void Collie_MIC_init(void)
- {
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_MIC, "Collie_MIC_init");
- /* MIC to GPIO 17 */
- /* alternate functions for the GPIOs */
-- GAFR &= ~( COLLIE_GPIO_MIC );
--
-+ GAFR &= ~( COLLIE_GPIO_MIC );
- /* Set the direction: 17 output */
- GPDR |= ( COLLIE_GPIO_MIC );
--
--#if defined(CONFIG_COLLIE_TR1)
-- /* Set pin level (Low) */
-- GPCR = ( COLLIE_GPIO_MIC );
--#else
- /* Set pin level (High) */
- GPSR = ( COLLIE_GPIO_MIC );
--#endif
-- LEAVE(TRACE_MIC, "Collie_MIC_init");
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
- }
-
- static inline void Collie_MIC_on(void)
- {
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_MIC, "Collie_MIC_on");
--#if defined(CONFIG_COLLIE_TR1)
-- GPSR = ( COLLIE_GPIO_MIC );
--#else
- GPCR = ( COLLIE_GPIO_MIC );
--#endif
-- LEAVE(TRACE_MIC, "Collie_MIC_on");
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
- }
-
- static inline void Collie_MIC_off(void)
- {
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_MIC, "Collie_MIC_off");
-- if (!COLLE_RECORDING) {
--#if defined(CONFIG_COLLIE_TR1)
-- GPCR = ( COLLIE_GPIO_MIC );
--#else
-- GPSR = ( COLLIE_GPIO_MIC );
--#endif
-- }
-- LEAVE(TRACE_MIC, "Collie_MIC_off");
--#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
--}
--
--static inline void Collie_volume_init(void)
--{
-- ENTER(TRACE_VOLUME, "Collie_volume_init");
-- m62332_senddata(0, M62332_EVR_CH);
-- collie_volume = 0;
-- LEAVE(TRACE_VOLUME, "Collie_volume_init");
--}
--
--static inline void Collie_volume_on(void)
--{
-- ENTER(TRACE_VOLUME, "Collie_volume_on");
-- if (collie_volume != sound.volume_left) {
-- //Collie_hard_mute_on();
-- m62332_senddata(0xff * sound.volume_left / 100, M62332_EVR_CH);
-- //Collie_hard_mute_off();
-- collie_volume = sound.volume_left;
-- }
-- LEAVE(TRACE_VOLUME, "Collie_volume_on");
--}
--
--static inline void Collie_volume_off(void)
--{
-- ENTER(TRACE_VOLUME, "Collie_volume_off");
-- if (collie_volume) {
-- //Collie_hard_mute_on();
-- m62332_senddata(0, M62332_EVR_CH);
-- //Collie_hard_mute_off();
-- collie_volume = 0;
-- }
-- LEAVE(TRACE_VOLUME, "Collie_volume_off");
--}
--
--#define VOL_THRES 40
--static void Collie_volume_half_adjust(void)
--{
-- int volume = collie_volume;
-- ENTER(TRACE_VOLUME, "Collie_volume_half_adjust");
-- if (collie_volume > sound.volume_left) {
-- /* volume down */
-- if (collie_volume > VOL_THRES) {
-- if (sound.volume_left > VOL_THRES) {
-- volume = (collie_volume + sound.volume_left)/2;
-- if (volume == collie_volume) {
-- volume = sound.volume_left;
-- }
-- } else {
-- volume = (collie_volume + VOL_THRES)/2;
-- if (volume == collie_volume) {
-- volume = VOL_THRES;
-- }
-- }
-- } else {
-- /* we can pull down without noise */
-- volume = sound.volume_left;
-- }
-- } else if (collie_volume < sound.volume_left) {
-- /* volume up */
-- if (sound.volume_left > VOL_THRES) {
-- if (collie_volume < VOL_THRES) {
-- /* we can pull up to VOL_THRES without noise */
-- volume = VOL_THRES;;
-- } else {
-- volume = (collie_volume + sound.volume_left)/2;
-- if (volume == collie_volume) {
-- volume = sound.volume_left;
-- }
-- }
-- } else {
-- /* we can pull up without noise */
-- volume = sound.volume_left;
-- }
-- }
-- if (collie_volume != volume) {
-- m62332_senddata(0xff * volume / 100, M62332_EVR_CH);
-- collie_volume = volume;
-- }
-- LEAVE(TRACE_VOLUME, "Collie_volume_half_adjust");
--}
--
--static void Collie_volume_half_off(void)
--{
-- int volume;
-- int delta = 1;
-- ENTER(TRACE_VOLUME, "Collie_volume_half_off");
-- while (0 < collie_volume) {
-- if (collie_volume <= VOL_THRES) {
-- volume = 0;
-- } else {
-- if (collie_volume > delta) {
-- volume = collie_volume - delta;
-- } else {
-- volume = 0;
-- }
-- if (volume && volume < VOL_THRES) {
-- volume = VOL_THRES;
-- }
-- delta <<= 1;
-- }
-- m62332_senddata(0xff * volume / 100, M62332_EVR_CH);
-- collie_volume = volume;
-- udelay(100);
-- }
-- LEAVE(TRACE_VOLUME, "Collie_volume_half_off");
--}
--
--static void Collie_OP_SHDN_on(void)
--{
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_OP_SHDN,"Collie_OP_SHDN_on");
-- if (!collie_op_shdn_on) {
-- /* set volume */
-- Collie_volume_off();
--
-- /* OP_SHDN to GPIO 17 */
-- /* alternate functions for the GPIOs */
-- GAFR &= ~( COLLIE_GPIO_OPSHDN );
--
-- /* Set the direction: 17 output */
-- GPDR |= ( COLLIE_GPIO_OPSHDN );
--
-- /* Set pin level (high) */
-- GPSR |= ( COLLIE_GPIO_OPSHDN );
--
-- /* set volume */
-- Collie_volume_on();
--
-- collie_op_shdn_on = 1;
-- }
-- LEAVE(TRACE_OP_SHDN,"Collie_OP_SHDN_on");
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
--}
--
--static void Collie_OP_SHDN_off(void)
--{
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_OP_SHDN,"Collie_OP_SHDN_off");
-- /* OP_SHDN to GPIO 17 */
-- /* alternate functions for the GPIOs */
-- GAFR &= ~( COLLIE_GPIO_OPSHDN );
--
-- /* Set the direction: 17 output */
-- GPDR |= ( COLLIE_GPIO_OPSHDN );
--
-- /* Clear pin level (low) */
-- GPCR |= ( COLLIE_GPIO_OPSHDN );
--
-- collie_op_shdn_on = 0;
-- LEAVE(TRACE_OP_SHDN,"Collie_OP_SHDN_off");
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
-+ GPSR = ( COLLIE_GPIO_MIC );
- }
-
- static inline void Collie_ssp_init(void)
- {
-- ENTER(TRACE_SSP, "Collie_ssp_init");
- /* alternate functions for the GPIOs */
- /* SSP port to GPIO 10,12,13, 19 */
- GAFR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK );
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- /* SSP port to GPIO 11 */
-- GAFR |= GPIO_SSP_RXD;
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
-
- /* Set the direction: 10, 12, 13 output; 19 input */
- GPDR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM );
- GPDR &= ~( GPIO_SSP_CLK );
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- /* Set the direction: 11 input */
-- GPDR &= ~( GPIO_SSP_RXD );
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
-
- /* enable SSP pin swap */
- PPAR |= PPAR_SPR;
-@@ -1516,400 +666,162 @@
- /* the SSP setting */
- Ser4SSCR0 = (SSCR0_DataSize(16) | SSCR0_TI | SSCR0_SerClkDiv(2));
- Ser4SSCR1 = (SSCR1_SClkIactL | SSCR1_SClk1P | SSCR1_ExtClk);
--
-- LEAVE(TRACE_SSP, "Collie_ssp_init");
- }
-
- static inline void Collie_ssp_on(void)
- {
-- ENTER(TRACE_SSP, "Collie_ssp_on");
- /* turn on the SSP */
- Ser4SSCR0 |= ( SSCR0_SSE );
-- LEAVE(TRACE_SSP, "Collie_ssp_on");
- }
-
- static inline void Collie_ssp_off(void)
- {
-- ENTER(TRACE_SSP, "Collie_ssp_off");
- /* turn off the SSP */
- Ser4SSCR0 &= ~( SSCR0_SSE );
-- LEAVE(TRACE_SSP, "Collie_ssp_off");
--}
--
--static inline void Collie_sound_hard_init(void)
--{
-- ENTER(TRACE_ON, "Collie_sound_hard_init");
-- Collie_hard_mute_init();
-- Collie_audio_clock_init();
-- Collie_paif_init();
-- Collie_volume_init();
-- Collie_ssp_init();
-- Collie_MIC_init();
--
-- Collie_FS8KLPF_start();
-- LEAVE(TRACE_ON, "Collie_sound_hard_init");
--}
--
--static inline void Collie_sound_hard_term(void)
--{
-- ENTER(TRACE_ON, "Collie_sound_hard_term");
--#ifdef DAC_OFF_WITH_DEVICE_OFF
-- /* DAC Off */
-- Collie_DAC_off();
--#endif
-- LEAVE(TRACE_ON, "Collie_sound_hard_term");
--}
--
--static void Collie_FS8KLPF_start(void)
--{
--#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
-- ENTER(TRACE_ON,"Collie_FS8KLPF_start");
-- /* Set up TC35143 GPIO I/O Direction (GPIO5 output mode) */
-- ucb1200_set_io_direction(TC35143_GPIO_FS8KLPF,
-- TC35143_IODIR_OUTPUT);
-- /* Set up TC35143 GPIO 5 (set LOW) */
-- ucb1200_set_io(TC35143_GPIO_FS8KLPF, TC35143_IODAT_LOW);
-- LEAVE(TRACE_ON,"Collie_FS8KLPF_start");
--#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
--}
--
--#ifdef CONFIG_PM
--#if 0
--static void Collie_FS8KLPF_stop(void)
--{
-- /* Set up TC35143 GPIO I/O Direction (GPIO5 output mode) */
-- ucb1200_set_io_direction(TC35143_GPIO_FS8KLPF,
-- TC35143_IODIR_OUTPUT);
-- /* Set up TC35143 GPIO 5 (set LOW) */
-- ucb1200_set_io(TC35143_GPIO_FS8KLPF, TC35143_IODAT_HIGH);
--}
--
--static void Collie_clock_stop(void)
--{
-- /* LoCoMo PCM audio interface */
-- Collie_paif_off();
--
-- /* LoCoMo audio clock off */
-- Collie_audio_clock_off();
--}
--#endif
--#endif
--
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */
--static unsigned long in_timehandle = 0;
--static struct timer_list timer;
--
--static void collieDoDelayedSilence(void)
--{
-- ENTER(TRACE_ON,"collieDoDelayedSilence");
-- down(&df_sem);
-- if(isDelayed(DELAY_HARD_MUTE_ON)) {
-- Collie_hard_mute_on();
-- }
-- if(isDelayed(DELAY_DAC_OFF)) {
-- Collie_DAC_off();
-- }
-- ResetDelayAll();
-- up(&df_sem);
-- LEAVE(TRACE_ON,"colliDoDelayedSilence");
--}
--
--static void collieDelayedSilence(void)
--{
-- ENTER(TRACE_ON,"collieDelayedSilence");
-- while (1) {
-- sleep_on(&delay_off);
-- collieDoDelayedSilence();
-- }
-- LEAVE(TRACE_ON,"collieDelayedSilence");
--}
--
--static void collieStartDelayedSilence(unsigned long data)
--{
-- ENTER(TRACE_ON,"collieStartDelayedSilence");
-- in_timehandle = 0;
-- wake_up(&delay_off);
-- LEAVE(TRACE_ON,"collieStartDelayedSilence");
--}
--
--static void collieTriggerDelayedSilence(void)
--{
-- ENTER(TRACE_ON,"collieTriggerDelayedSilence");
-- in_timehandle = 1;
-- init_timer(&timer);
-- timer.function = collieStartDelayedSilence;
-- timer.expires = jiffies + 5*100;
-- add_timer(&timer);
-- LEAVE(TRACE_ON,"collieTriggerDelayedSilence");
--}
--
--static void collieCancelDelayedSilence(void)
--{
-- ENTER(TRACE_ON,"collieCancelDelayedSilence");
-- down(&df_sem);
-- ResetDelayAll();;
-- up(&df_sem);
-- if (in_timehandle) {
-- del_timer(&timer);
-- in_timehandle = 0;
-- }
-- LEAVE(TRACE_ON,"collieCancelDelayedSilence");
--}
--#endif
--
--static void Collie_disable_sound(void)
--{
-- ENTER(TRACE_ON,"Collie_disable_sound");
-- sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
-- sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
--#ifndef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.18 */
-- Collie_volume_half_off();
-- Collie_hard_mute_on();
-- Collie_soft_mute_on();
--
-- Collie_ssp_off();
--
-- /* Collie_clock_stop(); */
--#endif
-- LEAVE(TRACE_ON,"Collie_disable_sound");
--}
--
--static void CollieSilence(void)
--{
-- ENTER(TRACE_ON,"CollieSilence");
-- /* Disable sound & DMA */
-- Collie_disable_sound();
--
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.18 */
-- Collie_volume_half_off();
-- Collie_hard_mute_delay_on();
-- Collie_soft_mute_on();
--
-- Collie_ssp_off();
--
-- /* Collie_clock_stop(); */
--#endif
--
--#if 0 /* H.Hayami SHARP 2001.12.18 */
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \
-- !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
-- Collie_volume_off();
--#endif
--#endif
-- Collie_OP_SHDN_off();
-- Collie_soft_DAC_off();
-- Collie_paif_off();
-- Collie_audio_clock_off();
--
-- //Collie_MIC_on();
--
--#ifndef DAC_OFF_WITH_DEVICE_OFF
-- /* DAC Off */
--#ifdef TRY_DELAY_OFF /* H.Hayami 2001.12.15 */
-- Collie_DAC_delay_off();
--#else
-- Collie_DAC_off();
--#endif
--#endif /* end DAC_OFF_WITH_DEVICE_OFF */
--
-- /* AMP Off */
-- Collie_AMP_off();
--
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.18 */
-- collieTriggerDelayedSilence();
--#endif
-- LEAVE(TRACE_ON,"CollieSilence");
--}
--
--static int CollieGetSamp(void)
--{
-- ENTER(TRACE_ON,"CollieGetSamp");
-- switch (sound.soft.speed) {
-- case 8000:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[7];
-- case 44100:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[0];
-- case 22050:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[1];
-- case 11025:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[2];
-- case 48000:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[3];
-- case 32000:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[4];
-- case 24000:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[5];
-- case 16000:
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[6];
-- default:
-- printk("Collie sound: Illegal sound rate %d\n", sound.soft.speed);
-- LEAVE(TRACE_ON,"CollieGetSamp");
-- return clock_set_data[7];
-- }
--}
--
--static inline void Collie_DAC_sendbit(int bit_data)
--{
-- ENTER(TRACE_SENDDATA,"Collie_DAC_sendbit");
-- if (bit_data & 1) {
-- LCM_GPO |= (LCM_GPIO_DAC_SDATA);
-- } else {
-- LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
-- }
--
-- udelay(1);
-- LCM_GPO |= (LCM_GPIO_DAC_SCK);
--
-- udelay(1);
-- LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
-- udelay(1);
-- LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
-- udelay(1);
-- LEAVE(TRACE_SENDDATA,"Collie_DAC_sendbit");
--}
--
--static void Collie_DAC_sendword(int data)
--{
-- int i;
--
-- ENTER(TRACE_SENDDATA,"Collie_DAC_sendword");
--#if defined(CONFIG_COLLIE_PCM1741)
--
-- LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
-- udelay(1);
-- LCM_GPO |= (LCM_GPIO_DAC_SLOAD);
-- udelay(1);
--
-- for (i = 0; i < 16; i++)
-- Collie_DAC_sendbit(data >> (15 - i));
--
-- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-- udelay(2);
--
--#elif defined(CONFIG_COLLIE_PCM1717)
--
-- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-- udelay(1000);
-- LCM_GPO |= (LCM_GPIO_DAC_SLOAD);
-- udelay(1000);
-- LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
-- udelay(1000);
--
-- for (i = 0; i < 16; i++)
-- Collie_DAC_sendbit(data >> (15 - i));
--
-- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-- udelay(1000);
-- LCM_GPO |= (LCM_GPIO_DAC_SLOAD);
-- udelay(1000);
-- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
-- udelay(1000);
--
--#endif
-- LEAVE(TRACE_SENDDATA,"Collie_DAC_sendword");
- }
-
--void
--Collie_audio_power_on(void)
-+
-+static inline void Collie_sound_hard_init(void)
- {
-- int send_data;
-+ Collie_hard_mute_init();
-+ Collie_audio_clock_init();
-+ Collie_paif_off();
-+ Collie_volume_init();
-+ Collie_ssp_init();
-+ Collie_MIC_init();
-+ Collie_soft_mute_on();
-+ Collie_DAC_on();
-+}
-
-- ENTER(TRACE_ON,"Collie_audio_power_on");
-+void Collie_recording_on(void)
-+{
-+ collie_recording=1;
-+ if (!playing)
-+ Collie_DAC_on();
-+ else
-+ Collie_hard_mute_left_on();
-+ Collie_MIC_on();
-+}
-
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */
-- collieCancelDelayedSilence();
--#endif
-+void Collie_recording_off(void)
-+{
-+ collie_recording=0;
-+ Collie_MIC_off();
-+ if (!playing)
-+ Collie_DAC_off();
-+ else
-+ Collie_hard_mute_left_off();
-+}
-
-+static void Collie_audio_power_on(void)
-+{
-+ playing=1;
- collie_amp_init = 0;
--
-- /* OP_SHDN off */
-- Collie_OP_SHDN_off();
--
-- /* AMP on */
-- Collie_AMP_on();
--
-- /* DAC ON */
-- Collie_DAC_on();
--
-- Collie_MIC_off();
-- Collie_ssp_on();
--
-- /* LoCoMo Audio clock */
-- Collie_audio_clock_off();
-+ if (!collie_recording)
-+ Collie_DAC_on();
-+ Collie_ssp_on();
-+ Collie_audio_clock_off(); /* LoCoMo Audio clock */
- Collie_audio_clock_on();
--
-- /* LoCoMo PCM audio interface */
-- Collie_paif_on();
--
-+ Collie_paif_on(); /* LoCoMo PCM audio interface */
- udelay(1000);
--
-- /* DAC Setting */
- Collie_DAC_init();
--
- Collie_soft_DAC_on();
-- Collie_soft_mute_init();
-+ Collie_soft_mute_off();
-+ Collie_hard_mute_off();
-+ if (collie_recording)
-+ Collie_hard_mute_left_on();
-+ Collie_volume_set(sound.volume);
-+}
-
-- sound.hard = sound.soft;
-+static void Collie_audio_power_off(void){ /* Disable sound only */
-+ Collie_volume_set(0);
-+ Collie_hard_mute_on();
-+ Collie_soft_mute_on();
-+ Collie_ssp_off();
-+ Collie_soft_DAC_off();
-+ Collie_paif_off();
-+ Collie_audio_clock_off();
-+ if (!collie_recording)
-+ Collie_DAC_off();
-+ playing=0;
-+}
-
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \
-- !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
-- /* Volume set */
-- Collie_volume_half_adjust();
-- {
-- int i;
-- for (i=0; i<10*1000; i++) {
-- udelay(1);
-+
-+static inline void Collie_volume_init(void)
-+{
-+ m62332_senddata(0, M62332_EVR_CH);
-+ collie_volume = 0;
-+}
-+
-+#define VOL_THRES 10
-+
-+static void Collie_volume_set(int dest)
-+{
-+ int chn;
-+ while (dest != collie_volume) {
-+ chn = dest-collie_volume;
-+ if (chn>VOL_THRES)
-+ chn=VOL_THRES;
-+ else if (chn<-VOL_THRES)
-+ chn=-VOL_THRES;
-+ if (chn) {
-+ collie_volume += chn;
-+ m62332_senddata(0xff * collie_volume / 100, M62332_EVR_CH);
- }
-+ udelay(100);
- }
--#endif
-+}
-
-- Collie_soft_mute_off();
-- Collie_hard_mute_off();
-+static int sound_set_speed(int speed)
-+{
-+ if (speed < 0) {
-+ return(sound.speed);
-+ }
-+
-+ if (speed<8000) sound.speed=8000;
-+ else if (speed<=11025) sound.speed=11025;
-+ else if (speed<=16000) sound.speed=16000;
-+ else if (speed<=22050) sound.speed=22050;
-+ else if (speed<=24000) sound.speed=24000;
-+ else if (speed<=32000) sound.speed=32000;
-+ else if (speed<=44100) sound.speed=44100;
-+ else sound.speed=48000;
-+
-+ /* LoCoMo Audio clock */
-+ Collie_audio_clock_off();
-+ Collie_audio_clock_on();
-+ return(sound.speed);
-+}
-
-- LEAVE(TRACE_ON,"Collie_audio_power_on");
-+/*** Mid level stuff *********************************************************/
-+
-+static void Collie_Set_Volume(int volume)
-+{
-+ sound.volume = volume & 0xff;
-+ sound.volume += ( volume & 0xff00 >> 8);
-+ sound.volume >>=1;
-+ if (sound.volume>100) sound.volume=100;
- }
-
--static void CollieInit(void)
-+static int Collie_Get_Volume(void)
- {
-- ENTER(TRACE_ON,"CollieInit");
-- sound.hard = sound.soft;
-- LEAVE(TRACE_ON,"CollieInit");
-+ return ( sound.volume << 8 | sound.volume );
- }
-
-+
- static void Collie_sq_interrupt(void* id, int size)
- {
- audio_buf_t *b = (audio_buf_t *) id;
-- ENTER(TRACE_INTERRUPT,"Collie_sq_interrupt");
--/***** DEBUG *****
--printk("Collie_sq_interrupt: Start\n");
--*****************/
-+
- /*
- * Current buffer is sent: wake up any process waiting for it.
- */
-- ENTER(TRACE_SEM,"up sem");
- up(&b->sem);
-- LEAVE(TRACE_SEM,"up sem");
--/***** DEBUG *****
--printk("Collie_sq_interrupt: up End\n");
--*****************/
- /* And any process polling on write. */
-- ENTER(TRACE_SEM,"up wait");
-- wake_up(&b->sem.wait);
-- LEAVE(TRACE_SEM,"up wait");
--/***** DEBUG *****
--printk("Collie_sq_interrupt: wake_up End\n");
--*****************/
-+ wake_up_interruptible(&b->sem.wait);
-+ /* And indicate which was the last buffer sent */
-
- DPRINTK("Collie_sq_interrupt \n");
-- LEAVE(TRACE_INTERRUPT,"Collie_sq_interrupt");
- }
-
-
-@@ -1917,191 +829,52 @@
- {
- int err;
-
-- ENTER(TRACE_ON,"CollieIrqInit");
- err = sa1100_request_dma(&collie_dmasound_irq, "dmasound",
- DMA_Ser4SSPWr);
- if (err) {
-- LEAVE(TRACE_ON,"CollieIrqInit");
- return 0;
- }
-- /* printk("collie_dmasound_irq=%d\n", collie_dmasound_irq); */
-+ printk("collie_dmasound_irq=%d\n", collie_dmasound_irq);
-
- sa1100_dma_set_callback(collie_dmasound_irq,
- (dma_callback_t)Collie_sq_interrupt);
-
--
-- /* Disable sound & DMA */
-- Collie_disable_sound();
--
-- LEAVE(TRACE_ON,"CollieIrqInit");
-+ sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
-+ sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
-+ Collie_audio_power_off();
- return(1);
--
--}
--
--#ifdef MODULE
--static void CollieIrqCleanUp(void)
--{
-- ENTER(TRACE_ON,"CollieIrqCleanUp");
-- /* Disable sound & DMA */
-- Collie_disable_sound();
--
-- /* release the interrupt */
-- free_irq(IRQ_DMA, Collie_sq_interrupt);
-- LEAVE(TRACE_ON,"CollieIrqCleanUp");
- }
--#endif /* MODULE */
--
-
- static int CollieSetFormat(int format)
- {
- int size;
-
-- ENTER(TRACE_ON,"CollieSetFormat");
-- /* Falcon sound DMA supports 8bit and 16bit modes */
--
- switch (format) {
- case AFMT_QUERY:
-- LEAVE(TRACE_ON,"CollieSetFormat");
-- return(sound.soft.format);
-- case AFMT_MU_LAW:
-- size = 8;
-- ct_func = sound.trans->ct_ulaw;
-- break;
-- case AFMT_A_LAW:
-- size = 8;
-- ct_func = sound.trans->ct_alaw;
-- break;
-- case AFMT_S8:
-- size = 8;
-- ct_func = sound.trans->ct_s8;
-- break;
-- case AFMT_U8:
-- size = 8;
-- ct_func = sound.trans->ct_u8;
-- break;
-- case AFMT_S16_BE:
-- size = 16;
-- ct_func = sound.trans->ct_s16be;
-- break;
-- case AFMT_U16_BE:
-- size = 16;
-- ct_func = sound.trans->ct_u16be;
-- break;
-- case AFMT_S16_LE:
-- size = 16;
-- ct_func = sound.trans->ct_s16le;
-- break;
-- case AFMT_U16_LE:
-+ return(sound.format);
-+ default: /* This is the only one supported by the hardware it seems */
- size = 16;
-- ct_func = sound.trans->ct_u16le;
-- break;
-- default: /* :-) */
-- size = 8;
-- format = AFMT_S8;
-- }
--
-- sound.soft.format = format;
-- sound.soft.size = size;
-- if (sound.minDev == SND_DEV_DSP) {
-- sound.dsp.format = format;
-- sound.dsp.size = sound.soft.size;
-+ format = AFMT_S16_LE;
- }
-+ sound.format = format;
-+ sound.size = size;
-
-- LEAVE(TRACE_ON,"CollieSetFormat");
- return(format);
- }
-
--/*** Machine definitions *****************************************************/
--
--static MACHINE machCollie = {
-- DMASND_COLLIE, // int type
-- NULL, // void *dma_alloc(uint, int)
-- NULL, // void dma_free(void *, uint)
-- CollieIrqInit, // void irqinit(void)
--#ifdef MODULE
-- CollieIrqCleanUp, // void irqcleanup(void)
--#endif /* MODULE */
-- CollieInit, // void init(void)
-- CollieSilence, // void silence(void)
-- CollieSetFormat, // int setFormat(int)
-- NULL, // int setVolume(int)
-- NULL, // int setBass(int)
-- NULL, // int setTreble(int)
-- NULL, // int setGain(int)
-- NULL // void play(void)
--};
--
--
--/*** Mid level stuff *********************************************************/
--
--
--static void sound_silence(void)
--{
-- ENTER(TRACE_ON,"sound_silence");
-- /* update hardware settings one more */
-- //(*sound.mach.init)();
-- (*sound.mach.silence)();
-- LEAVE(TRACE_ON,"sound_silence");
--
--}
--
--
--static void sound_init(void)
--{
-- ENTER(TRACE_ON,"sound_init");
-- (*sound.mach.init)();
-- LEAVE(TRACE_ON,"sound_init");
--}
--
--
--static int sound_set_format(int format)
--{
-- ENTER(TRACE_ON,"sound_set_format");
-- LEAVE(TRACE_ON,"sound_set_format");
-- return(*sound.mach.setFormat)(format);
--}
--
--
--static int sound_set_speed(int speed)
--{
-- ENTER(TRACE_ON,"sound_set_speed");
-- if (speed < 0) {
-- LEAVE(TRACE_ON,"sound_set_speed");
-- return(sound.soft.speed);
-- }
--
-- sound.soft.speed = speed;
-- (*sound.mach.init)();
-- if (sound.minDev == SND_DEV_DSP)
-- sound.dsp.speed = sound.soft.speed;
--
-- /* LoCoMo Audio clock */
-- Collie_audio_clock_off();
-- Collie_audio_clock_on();
--
-- LEAVE(TRACE_ON,"sound_set_speed");
-- return(sound.soft.speed);
--}
-
-
- static int sound_set_stereo(int stereo)
- {
-- ENTER(TRACE_ON,"sound_set_stereo");
-+/* Only stereo is supported by hardware */
- if (stereo < 0) {
-- LEAVE(TRACE_ON,"sound_set_stereo");
-- return(sound.soft.stereo);
-+ return(sound.stereo);
- }
-+ return(1);
-+}
-
-- stereo = !!stereo; /* should be 0 or 1 now */
--
-- sound.soft.stereo = stereo;
-- if (sound.minDev == SND_DEV_DSP)
-- sound.dsp.stereo = stereo;
-- //(*sound.mach.init)();
-
-- LEAVE(TRACE_ON,"sound_set_stereo");
-- return(stereo);
--}
-+/* Higher level stuff ************************************************/
-
- /*
- * /dev/mixer abstraction
-@@ -2109,20 +882,15 @@
-
- static int mixer_open(struct inode *inode, struct file *file)
- {
-- ENTER(TRACE_ON,"mixer_open");
- MOD_INC_USE_COUNT;
- mixer.busy = 1;
-- LEAVE(TRACE_ON,"mixer_open");
- return 0;
- }
-
--
- static int mixer_release(struct inode *inode, struct file *file)
- {
-- ENTER(TRACE_ON,"mixer_release");
- mixer.busy = 0;
- MOD_DEC_USE_COUNT;
-- LEAVE(TRACE_ON,"mixer_release");
- return 0;
- }
-
-@@ -2132,58 +900,37 @@
- {
- int data;
-
-- ENTER(TRACE_ON,"mixer_ioctl");
-- switch (sound.mach.type) {
-- case DMASND_COLLIE:
-- {
-- switch (cmd) {
-- case SOUND_MIXER_READ_DEVMASK:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, SOUND_MASK_VOLUME );
-- case SOUND_MIXER_READ_RECMASK:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
-- case SOUND_MIXER_READ_STEREODEVS:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
-- case SOUND_MIXER_READ_CAPS:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
--
-- case SOUND_MIXER_WRITE_VOLUME:
-- IOCTL_IN(arg, data);
-- Collie_Set_Volume(data);
-- case SOUND_MIXER_READ_VOLUME:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, Collie_Get_Volume());
--
-- case SOUND_MIXER_READ_TREBLE:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
-- case SOUND_MIXER_WRITE_TREBLE:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
--
-- case SOUND_MIXER_WRITE_MIC:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
-- case SOUND_MIXER_READ_MIC:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
--
-- case SOUND_MIXER_READ_SPEAKER:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
-- case SOUND_MIXER_WRITE_SPEAKER:
-- LEAVE(TRACE_ON,"mixer_ioctl");
-- return IOCTL_OUT(arg, 0);
-- }
-- break;
-- }
-- }
-- LEAVE(TRACE_ON,"mixer_ioctl");
-+ switch (cmd) {
-+ case SOUND_MIXER_READ_DEVMASK:
-+ return IOCTL_OUT(arg, headphone ? SOUND_MASK_VOLUME : 0 );
-+ case SOUND_MIXER_READ_RECMASK:
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_READ_STEREODEVS:
-+ return IOCTL_OUT(arg, headphone ? SOUND_MASK_VOLUME : 0 );
-+ case SOUND_MIXER_READ_CAPS:
-+ return IOCTL_OUT(arg, 0);
-+
-+ case SOUND_MIXER_WRITE_VOLUME:
-+ IOCTL_IN(arg, data);
-+ Collie_Set_Volume(data);
-+ case SOUND_MIXER_READ_VOLUME:
-+ return IOCTL_OUT(arg, Collie_Get_Volume());
-+ case SOUND_MIXER_READ_TREBLE:
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_WRITE_TREBLE:
-+ return IOCTL_OUT(arg, 0);
-+
-+ case SOUND_MIXER_WRITE_MIC:
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_READ_MIC:
-+ return IOCTL_OUT(arg, 0);
-+
-+ case SOUND_MIXER_READ_SPEAKER:
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_WRITE_SPEAKER:
-+ return IOCTL_OUT(arg, 0);
-+ }
- return -EINVAL;
--
- }
-
-
-@@ -2198,32 +945,13 @@
-
- static void __init mixer_init(void)
- {
--#ifndef MODULE
-- int mixer_unit;
--#endif
-- ENTER(TRACE_ON,"mixer_init");
- mixer_unit = register_sound_mixer(&mixer_fops, -1);
- if (mixer_unit < 0) {
-- LEAVE(TRACE_ON,"mixer_init");
- return;
- }
--
- mixer.busy = 0;
-- sound.treble = 0;
-- sound.bass = 0;
-- switch (sound.mach.type) {
-- case DMASND_COLLIE:
-- // sound.volume_left = 0x3c;
-- // sound.volume_right = 0x3c;
-- sound.volume_left = 80;
-- sound.volume_right = 80;
-- collie_main_volume = sound.volume_left;
-- break;
-- }
--
-- // printk("mixer_init : ret \n");
--
-- LEAVE(TRACE_ON,"mixer_init");
-+ sound.volume = 80;
-+ Collie_volume_set(sound.volume);
- }
-
- /* This function allocates the buffer structure array and buffer data space
-@@ -2237,11 +965,9 @@
- char *dmabuf = 0;
- dma_addr_t dmaphys = 0;
-
-- ENTER(TRACE_ON,"sq_allocate_buffers");
- DPRINTK("sq_allocate_buffers\n");
-
- if (s->buffers) {
-- LEAVE(TRACE_ON,"sq_allocate_buffers");
- return -EBUSY;
- }
-
-@@ -2279,10 +1005,8 @@
-
- b->start = dmabuf;
- b->dma_addr = dmaphys;
-+ b->idx = frag;
- sema_init(&b->sem, 1);
-- DPRINTK("buf %d: start %p dma %p\n", frag, b->start,
-- b->dma_addr);
--
- dmabuf += s->fragsize;
- dmaphys += s->fragsize;
- dmasize -= s->fragsize;
-@@ -2291,13 +1015,12 @@
- s->buf_idx = 0;
- s->buf = &s->buffers[0];
-
-- LEAVE(TRACE_ON,"sq_allocate_buffers");
-+
- return 0;
-
- err:
- printk("sound driver : unable to allocate audio memory\n ");
- sq_release_buffers(s);
-- LEAVE(TRACE_ON,"sq_allocate_buffers");
- return -ENOMEM;
- }
-
-@@ -2307,7 +1030,6 @@
-
- static void sq_release_buffers(audio_stream_t * s)
- {
-- ENTER(TRACE_ON,"sq_release_buffers");
- DPRINTK("sq_release_buffers\n");
-
- /* ensure DMA won't run anymore */
-@@ -2328,7 +1050,6 @@
-
- s->buf_idx = 0;
- s->buf = NULL;
-- LEAVE(TRACE_ON,"sq_release_buffers");
- }
-
- static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
-@@ -2339,27 +1060,20 @@
- u_char *dest;
- ssize_t uUsed, bUsed, bLeft, ret = 0;
-
-- ENTER(TRACE_WRITE,"sq_write");
- DPRINTK("sq_write: uLeft=%d\n", uLeft);
-
-- /* OP_SHDN on */
-- Collie_OP_SHDN_on();
--
- switch (file->f_flags & O_ACCMODE) {
- case O_WRONLY:
- case O_RDWR:
- break;
- default:
-- LEAVE(TRACE_WRITE,"sq_write1");
- return -EPERM;
- }
-
- if (!s->buffers && sq_allocate_buffers(s)) {
-- LEAVE(TRACE_WRITE,"sq_write2");
- return -ENOMEM;
- }
-
--#if 1
- if (collie_resume == 1) {
- int i;
- collie_resume = 0;
-@@ -2367,10 +1081,9 @@
- udelay(1);
- }
- }
--#endif
- #ifdef CONFIG_PM
- /* Auto Power off cancel */
-- autoPowerCancel = 0;
-+// autoPowerCancel = 0;
- #endif
-
- while (uLeft > 0) {
-@@ -2379,41 +1092,30 @@
- /* Wait for a buffer to become free */
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
-- ENTER(TRACE_SEM,"down_try sem");
- if (down_trylock(&b->sem)) {
-- LEAVE(TRACE_SEM,"down_try1 sem");
- break;
- }
-- LEAVE(TRACE_SEM,"down_try2 sem");
- } else {
- ret = -ERESTARTSYS;
-- ENTER(TRACE_SEM,"down_int sem");
-- //printk("### 0x%08x:%d\n", &b->sem.count, atomic_read(&b->sem.count));
- if (down_interruptible(&b->sem)) {
-- LEAVE(TRACE_SEM,"down_int1 sem");
- break;
- }
-- LEAVE(TRACE_SEM,"down_int2 sem");
- }
-
- dest = b->start + b->size;
- bUsed = 0;
- bLeft = s->fragsize - b->size;
-
-- if (ct_func) {
-- uUsed = ct_func(src, uLeft, dest, &bUsed, bLeft);
-+ if (collie_ct_s16) {
-+ uUsed = collie_ct_s16(src, uLeft, dest, &bUsed, bLeft);
- cpu_cache_clean_invalidate_range((unsigned long)dest,
- (unsigned long)(dest+(audio_fragsize)), 0);
- } else {
-- LEAVE(TRACE_WRITE,"sq_write3");
- return -EFAULT;
- }
-
- if (uUsed < 0) {
-- ENTER(TRACE_SEM,"up sem");
- up(&b->sem);
-- LEAVE(TRACE_SEM,"up sem");
-- LEAVE(TRACE_WRITE,"sq_write4");
- return -EFAULT;
- }
- src += uUsed;
-@@ -2421,9 +1123,7 @@
- b->size += bUsed;
-
- if (b->size < s->fragsize) {
-- ENTER(TRACE_SEM,"up sem");
- up(&b->sem);
-- LEAVE(TRACE_SEM,"up sem");
- break;
- }
-
-@@ -2431,7 +1131,7 @@
- sa1100_dma_queue_buffer(COLLIE_SOUND_DMA_CHANNEL,
- (void *) b, b->dma_addr, b->size);
-
-- Collie_volume_half_adjust();
-+ Collie_volume_set(sound.volume);
-
- b->size = 0; /* indicate that the buffer has been sent */
- NEXT_BUF(s, buf);
-@@ -2440,7 +1140,6 @@
- if ((src - buffer0))
- ret = src - buffer0;
- DPRINTK("sq_write: return=%d\n", ret);
-- LEAVE(TRACE_WRITE,"sq_write0");
- return ret;
- }
-
-@@ -2450,7 +1149,6 @@
- unsigned int mask = 0;
- int i;
-
-- ENTER(TRACE_ON,"sq_poll");
- DPRINTK("sq_poll(): mode=%s%s\n",
- (file->f_mode & FMODE_READ) ? "r" : "",
- (file->f_mode & FMODE_WRITE) ? "w" : "");
-@@ -2458,12 +1156,9 @@
- if (file->f_mode & FMODE_WRITE) {
- if (!output_stream.buffers
- && sq_allocate_buffers(&output_stream)) {
-- LEAVE(TRACE_ON,"sq_poll");
- return -ENOMEM;
- }
-- ENTER(TRACE_SEM,"poll_wait wait");
- poll_wait(file, &output_stream.buf->sem.wait, wait);
-- LEAVE(TRACE_SEM,"poll_wait wait");
- }
-
- if (file->f_mode & FMODE_WRITE) {
-@@ -2477,65 +1172,33 @@
- (mask & POLLIN) ? "r" : "",
- (mask & POLLOUT) ? "w" : "");
-
-- LEAVE(TRACE_ON,"sq_poll");
- return mask;
- }
-
- static int sq_open(struct inode *inode, struct file *file)
- {
-- ENTER(TRACE_ON,"sq_open");
- DPRINTK("sq_open\n");
-
- if (((file->f_flags & O_ACCMODE) == O_WRONLY)
- || ((file->f_flags & O_ACCMODE) == O_RDWR)) {
--#if 0
-- MOD_INC_USE_COUNT;
-- while(audio_wr_refcount) {
-- SLEEP(open_queue, ONE_SECOND);
-- if (SIGNAL_RECEIVED) {
-- MOD_DEC_USE_COUNT;
-- LEAVE(TRACE_ON,"sq_open");
-- return -EINTR;
-- }
-- }
--#else
- if (audio_wr_refcount) {
- DPRINTK(" sq_open EBUSY\n");
-- LEAVE(TRACE_ON,"sq_open");
- return -EBUSY;
- }
- MOD_INC_USE_COUNT;
--#endif
- audio_wr_refcount++;
- } else {
- DPRINTK(" sq_open EINVAL\n");
-- LEAVE(TRACE_ON,"sq_open");
- return -EINVAL;
- }
-
-- if (audio_wr_refcount == 1) {
-- DPRINTK("cold\n");
--
-- audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
-- audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
-- sq_release_buffers(&output_stream);
-- sound.minDev = MINOR(inode->i_rdev) & 0x0f;
-- sound.soft = sound.dsp;
-- sound.hard = sound.dsp;
--
-- if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
-- sound_set_speed(8000);
-- sound_set_stereo(0);
-- sound_set_format(AFMT_MU_LAW);
-- }
-- Collie_audio_power_on();
-- }
-
--#if 0
-- MOD_INC_USE_COUNT;
--#endif
-- LEAVE(TRACE_ON,"sq_open");
-- return 0;
-+ audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
-+ audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
-+ sq_release_buffers(&output_stream);
-+ output_stream.buf_idx=0;
-+ Collie_audio_power_on();
-+ return 0;
- }
-
- static int sq_fsync(struct file *filp, struct dentry *dentry)
-@@ -2543,11 +1206,9 @@
- audio_stream_t *s = &output_stream;
- audio_buf_t *b = s->buf;
-
-- ENTER(TRACE_ON,"sq_fsync");
- DPRINTK("sq_fsync\n");
-
- if (!s->buffers) {
-- LEAVE(TRACE_ON,"sq_fsync");
- return 0;
- }
-
-@@ -2557,12 +1218,10 @@
-
- #ifdef CONFIG_PM
- /* Auto Power off cancel */
-- autoPowerCancel = 0;
-+// autoPowerCancel = 0;
- #endif
-
-- ENTER(TRACE_SEM,"down sem");
- down(&b->sem);
-- LEAVE(TRACE_SEM,"down sem");
- sa1100_dma_queue_buffer(COLLIE_SOUND_DMA_CHANNEL,
- (void *) b, b->dma_addr, b->size);
- b->size = 0;
-@@ -2576,23 +1235,15 @@
- * - the buffer was already free thus nothing else to sync.
- */
- b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags);
-- ENTER(TRACE_SEM,"down-int sem");
- if (down_interruptible(&b->sem)) {
-- LEAVE(TRACE_SEM,"down-int sem");
-- LEAVE(TRACE_ON,"sq_fsync");
- return -EINTR;
- }
-- LEAVE(TRACE_SEM,"down-int sem");
-- ENTER(TRACE_SEM,"up sem");
- up(&b->sem);
-- LEAVE(TRACE_SEM,"up sem");
-- LEAVE(TRACE_ON,"sq_fsync");
- return 0;
- }
-
- static int sq_release(struct inode *inode, struct file *file)
- {
-- ENTER(TRACE_ON,"sq_release");
- DPRINTK("sq_release\n");
-
- switch (file->f_flags & O_ACCMODE) {
-@@ -2606,24 +1257,12 @@
- }
-
- if (!audio_wr_refcount) {
-- sound.soft = sound.dsp;
-- sound.hard = sound.dsp;
-- sound_silence();
-- Collie_OP_SHDN_off();
-+ sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
-+ sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
-+ Collie_audio_power_off();
- }
-
--#if 0
-- switch (file->f_flags & O_ACCMODE) {
-- case O_WRONLY:
-- case O_RDWR:
-- if (!audio_wr_refcount) {
-- WAKE_UP(open_queue);
-- }
-- }
--#endif
--
- MOD_DEC_USE_COUNT;
-- LEAVE(TRACE_ON,"sq_release");
- return 0;
- }
-
-@@ -2634,8 +1273,8 @@
- u_long fmt;
- int data;
- long val;
-+// audio_buf_info abinfo;
-
-- ENTER(TRACE_ON,"sq_ioctl");
- switch (cmd) {
- case SNDCTL_DSP_RESET:
- switch (file->f_flags & O_ACCMODE) {
-@@ -2643,11 +1282,9 @@
- case O_RDWR:
- sq_release_buffers(&output_stream);
- }
-- LEAVE(TRACE_ON,"sq_ioctl");
- return 0;
- case SNDCTL_DSP_POST:
- case SNDCTL_DSP_SYNC:
-- LEAVE(TRACE_ON,"sq_ioctl");
- return sq_fsync(file, file->f_dentry);
-
- /* ++TeSche: before changing any of these it's
-@@ -2656,59 +1293,34 @@
- case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
-- LEAVE(TRACE_ON,"sq_ioctl");
- return IOCTL_OUT(arg, sound_set_speed(data));
- case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
-- LEAVE(TRACE_ON,"sq_ioctl");
- return IOCTL_OUT(arg, sound_set_stereo(data));
-- case SOUND_PCM_WRITE_CHANNELS:
-+ case SNDCTL_DSP_CHANNELS:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
-- LEAVE(TRACE_ON,"sq_ioctl");
- return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
- case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
-- LEAVE(TRACE_ON,"sq_ioctl");
-- return IOCTL_OUT(arg, sound_set_format(data));
-+ return IOCTL_OUT(arg, CollieSetFormat(data));
- case SNDCTL_DSP_GETFMTS:
-- fmt = 0;
-- if (sound.trans) {
-- if (sound.trans->ct_ulaw)
-- fmt |= AFMT_MU_LAW;
-- if (sound.trans->ct_alaw)
-- fmt |= AFMT_A_LAW;
-- if (sound.trans->ct_s8)
-- fmt |= AFMT_S8;
-- if (sound.trans->ct_u8)
-- fmt |= AFMT_U8;
-- if (sound.trans->ct_s16be)
-- fmt |= AFMT_S16_BE;
-- if (sound.trans->ct_u16be)
-- fmt |= AFMT_U16_BE;
-- if (sound.trans->ct_s16le)
-- fmt |= AFMT_S16_LE;
-- if (sound.trans->ct_u16le)
-- fmt |= AFMT_U16_LE;
-- }
-- LEAVE(TRACE_ON,"sq_ioctl");
-+ fmt = AFMT_S16_LE;
- return IOCTL_OUT(arg, fmt);
- case SNDCTL_DSP_GETBLKSIZE:
-- LEAVE(TRACE_ON,"sq_ioctl");
- return IOCTL_OUT(arg, audio_fragsize);
- case SNDCTL_DSP_SUBDIVIDE:
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- if (output_stream.buffers) {
-- LEAVE(TRACE_ON,"sq_ioctl");
- return -EBUSY;
- }
- get_user(val, (long *) arg);
- audio_fragsize = 1 << (val & 0xFFFF);
-- if (audio_fragsize < 16)
-- audio_fragsize = 16;
-+ if (audio_fragsize < 256)
-+ audio_fragsize = 256;
- if (audio_fragsize > 16384)
- audio_fragsize = 16384;
- audio_nbfrags = (val >> 16) & 0x7FFF;
-@@ -2717,46 +1329,54 @@
- if (audio_nbfrags * audio_fragsize > 128 * 1024)
- audio_nbfrags = 128 * 1024 / audio_fragsize;
- if (sq_allocate_buffers(&output_stream)) {
-- LEAVE(TRACE_ON,"sq_ioctl");
- return -ENOMEM;
- }
-- LEAVE(TRACE_ON,"sq_ioctl");
- return 0;
-
--#if 1 // 2003.2.14
-+/* case SNDCTL_DSP_GETOSPACE:
-+ abinfo.fragsize = audio_fragsize;
-+ abinfo.fragstotal = audio_nbfrags;
-+ abinfo.fragments = lastsent-output_stream.buf_idx;
-+ if (abinfo.fragments<0)
-+ abinfo.fragments += abinfo.fragstotal;
-+ abinfo.bytes = abinfo.fragments*abinfo.fragsize;
-+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-+*/
- case SNDCTL_DSP_GETOSPACE:
- {
-- audio_buf_info inf = { 0, };
-+ audio_stream_t *s = &output_stream;
-+ audio_buf_info *inf = (audio_buf_info *) arg;
-+ int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
- int i;
-+ int frags = 0, bytes = 0;
-
-- if (!(file->f_mode & FMODE_WRITE))
-- return -EINVAL;
-- if (!output_stream.buffers && sq_allocate_buffers(&output_stream))
-- return -ENOMEM;
-- for (i = 0; i < output_stream.nbfrags; i++) {
-- if (atomic_read(&output_stream.buffers[i].sem.count) > 0) {
-- if (output_stream.buffers[i].size == 0)
-- inf.fragments++;
-- inf.bytes += output_stream.fragsize - output_stream.buffers[i].size;
-- }
-+ if (err)
-+ return err;
-+ if (output_stream.buffers) {
-+ for (i = 0; i < s->nbfrags; i++) {
-+ if (atomic_read(&s->buffers[i].sem.count) > 0) {
-+ if (s->buffers[i].size == 0) frags++;
-+ bytes += s->fragsize - s->buffers[i].size;
-+ }
-+ }
-+ put_user(s->nbfrags, &inf->fragstotal);
-+ put_user(s->fragsize, &inf->fragsize);
-+ } else {
-+ frags=audio_nbfrags;
-+ bytes=frags*audio_fragsize;
-+ put_user(frags, &inf->fragstotal);
-+ put_user(audio_fragsize, &inf->fragsize);
- }
-- inf.fragstotal = output_stream.nbfrags;
-- inf.fragsize = output_stream.fragsize;
-- return copy_to_user((void *)arg, &inf, sizeof(inf));
-+ put_user(frags, &inf->fragments);
-+ return put_user(bytes, &inf->bytes);
- }
--#endif
--
-
- default:
-- LEAVE(TRACE_ON,"sq_ioctl");
- return mixer_ioctl(inode, file, cmd, arg);
- }
-- LEAVE(TRACE_ON,"sq_ioctl");
- return -EINVAL;
- }
-
--
--
- static struct file_operations sq_fops =
- {
- llseek: sound_lseek,
-@@ -2770,40 +1390,18 @@
-
- static void __init sq_init(void)
- {
--#ifndef MODULE
-- int sq_unit;
--#endif
-- ENTER(TRACE_ON,"sq_init");
- sq_unit = register_sound_dsp(&sq_fops, -1);
- if (sq_unit < 0) {
-- LEAVE(TRACE_ON,"sq_init");
- return;
- }
-
-- /* whatever you like as startup mode for /dev/dsp,
-- * (/dev/audio hasn't got a startup mode). note that
-- * once changed a new open() will *not* restore these!
-- */
-- sound.dsp.format = AFMT_S16_LE;
--
-- sound.dsp.stereo = 0;
-- sound.dsp.size = 16;
--
-- /* set minimum rate possible without expanding */
-- switch (sound.mach.type) {
-- case DMASND_COLLIE:
-- sound.dsp.speed = 8000;
-- break;
-- }
--
-- /* before the first open to /dev/dsp this wouldn't be set */
-- sound.soft = sound.dsp;
-- sound.hard = sound.dsp;
-- sound.trans = &transCollie;
--
-- CollieSetFormat(sound.dsp.format);
-- sound_silence();
-- LEAVE(TRACE_ON,"sq_init");
-+ sound.format = AFMT_S16_LE;
-+ sound.stereo = 1;
-+ sound.speed = 44100;
-+
-+ CollieSetFormat(AFMT_S16_LE);
-+ Collie_audio_power_off();
-+ output_stream.buf=output_stream.buffers=NULL;
- }
-
- /*
-@@ -2816,9 +1414,7 @@
- char *buffer = state.buf;
- int len = 0;
-
-- ENTER(TRACE_ON,"state_open");
- if (state.busy) {
-- LEAVE(TRACE_ON,"state_open");
- return -EBUSY;
- }
-
-@@ -2828,8 +1424,8 @@
-
- len += sprintf(buffer+len, " COLLIE DMA sound driver:\n");
-
-- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
-- switch (sound.soft.format) {
-+ len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.format);
-+ switch (sound.format) {
- case AFMT_MU_LAW:
- len += sprintf(buffer+len, " (mu-law)");
- break;
-@@ -2857,22 +1453,19 @@
- }
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-- sound.soft.speed, sound.hard.speed);
-+ sound.speed, sound.speed);
- len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-- sound.soft.stereo,
-- sound.soft.stereo ? "stereo" : "mono");
-+ sound.stereo,
-+ sound.stereo ? "stereo" : "mono");
- state.len = len;
-- LEAVE(TRACE_ON,"state_open");
- return 0;
- }
-
-
- static int state_release(struct inode *inode, struct file *file)
- {
-- ENTER(TRACE_ON,"state_release");
- state.busy = 0;
- MOD_DEC_USE_COUNT;
-- LEAVE(TRACE_ON,"state_release");
- return 0;
- }
-
-@@ -2881,19 +1474,15 @@
- loff_t *ppos)
- {
- int n = state.len - state.ptr;
-- ENTER(TRACE_ON,"state_read");
- if (n > count)
- n = count;
- if (n <= 0) {
-- LEAVE(TRACE_ON,"state_read");
- return 0;
- }
- if (copy_to_user(buf, &state.buf[state.ptr], n)) {
-- LEAVE(TRACE_ON,"state_read");
- return -EFAULT;
- }
- state.ptr += n;
-- LEAVE(TRACE_ON,"state_read");
- return n;
- }
-
-@@ -2909,20 +1498,11 @@
-
- static void __init state_init(void)
- {
--#ifndef MODULE
-- int state_unit;
--#endif
-- ENTER(TRACE_ON,"state_unit");
- state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
- if (state_unit < 0) {
-- LEAVE(TRACE_ON,"state_unit");
- return;
- }
- state.busy = 0;
--
-- // printk("state_init : ret \n");
-- LEAVE(TRACE_ON,"state_unit");
--
- }
-
-
-@@ -2930,8 +1510,6 @@
-
- static long long sound_lseek(struct file *file, long long offset, int orig)
- {
-- ENTER(TRACE_ON,"sound_lseek");
-- LEAVE(TRACE_ON,"sound_lseek");
- return -ESPIPE;
- }
-
-@@ -2941,96 +1519,41 @@
- static int collie_sound_pm_callback(struct pm_dev *pm_dev,
- pm_request_t req, void *data)
- {
-- ENTER(TRACE_PM,"collie_sound_pm_callback");
- switch (req) {
- case PM_SUSPEND:
- #ifdef COLLIE_TRY_ONE
- disable_irq(IRQ_GPIO_nREMOCON_INT);
- #endif
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */
-- collieDoDelayedSilence();
-- collieCancelDelayedSilence();
--#endif
-- if (audio_wr_refcount == 1) {
-- Collie_volume_off();
-- Collie_hard_mute_on();
-- Collie_soft_mute_on();
-- sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
--
--#if 0 /* H.Hayami SHARP 2001.12.18 */
--#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \
-- !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
-- Collie_volume_off();
--#endif
--#endif
-- Collie_OP_SHDN_off();
-- Collie_soft_DAC_off();
-- Collie_paif_off();
-- Collie_audio_clock_off();
-- //Collie_MIC_on();
-- Collie_DAC_off();
-- Collie_AMP_off();
-- } else {
-- sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
-- }
-- Collie_sound_hard_term();
-+ sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
-+ Collie_audio_power_off();
- break;
- case PM_RESUME:
--/***** DEBUG *****g
--printk("collie_sound_pm_callback: audio_wr_refcount=%d\n", audio_wr_refcount);
--*****************/
-+
- #ifdef COLLIE_TRY_ONE
- enable_irq(IRQ_GPIO_nREMOCON_INT);
- #endif
--
-- Collie_sound_hard_init();
--
-- if (audio_wr_refcount == 1) {
-- collie_resume = 1;
--
-- Collie_audio_power_on();
--
-- sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
--#if 0 /* H.Hayami SHARP 2001.12.18 */
-- Collie_soft_mute_off();
-- Collie_hard_mute_off();
--#endif
-- } else {
-+ Collie_sound_hard_init(); /* this needs to be done! */
-+ collie_resume = 1;
-+ Collie_audio_power_off();
-+ if (audio_wr_refcount) Collie_audio_power_on();
-+ if (collie_recording) Collie_recording_on();
-+ sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
- #ifdef COLLIE_TRY_ONE
-- if ( !( GPLR & GPIO_nREMOCON_INT ) )
-+ if ( !( GPLR & GPIO_nREMOCON_INT ) )
- Collie_DAC_on();
- #endif
-- sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
-- }
--
--
- break;
--
- }
-- LEAVE(TRACE_PM,"collie_sound_pm_callback");
- return 0;
- }
- #endif
-
-
- #ifdef COLLIE_TRY_ONE
--
--static void collie_audio_on(void)
--{
-- while(1) {
-- sleep_on(&audio_on);
--
-- /* DAC ON */
-- Collie_DAC_on();
-- // printk("call audio on \n");
--
-- }
--}
--
- void Collie_rc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
-- // printk("int !\n");
-- wake_up(&audio_on);
-+ headphone=!headphone;
-+ printk("%s headphone \n",headphone ? "connected" : "disconnected");
- }
- #endif
-
-@@ -3038,113 +1561,85 @@
-
- int __init Collie_sound_init(void)
- {
-- int has_sound = 0;
--
--
-- ENTER(TRACE_ON,"Collie_sound_init");
-- has_sound = 1;
-- sound.mach = machCollie;
--
-- if (!has_sound) {
-- LEAVE(TRACE_ON,"Collie_sound_init");
-- return -1;
-- }
--
--#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */
-- sema_init(&df_sem, 1);
-- kernel_thread(collieDelayedSilence, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
--#endif
--
- Collie_sound_hard_init();
--
-- if (!sound.mach.irqinit()) {
-+ if (!CollieIrqInit()) {
- printk("Sound driver: Interrupt initialization failed\n");
-- LEAVE(TRACE_ON,"Collie_sound_init");
- return -1;
- }
--
-- /* Set up sound queue, /dev/audio and /dev/dsp. */
--
- /* Set default settings. */
- sq_init();
--
- /* Set up /dev/sndstat. */
- state_init();
--
- /* Set up /dev/mixer. */
- mixer_init();
--
- #ifdef MODULE
- irq_installed = 1;
- #endif
--
- printk("Collie Sound Driver Installed\n");
--
- #ifdef CONFIG_PM
- collie_sound_pm_dev = pm_register(PM_SYS_DEV, 0,
- collie_sound_pm_callback);
- #endif
--
--
- #ifdef COLLIE_TRY_ONE
- /* enable int sw */
- collie_rc_set_int_mode();
--
- /* GPIO15(int):IN, GPIO18(sw):OUT */
- GPDR = ((GPDR)&~GPIO_nREMOCON_INT)|GPIO_REMOCON_ADC_SW;
--
- /* GPIO15,18:not Alternate */
- GAFR &= ~(GPIO_nREMOCON_INT|GPIO_REMOCON_ADC_SW);
--
-+ /* Initialize headphone state */
-+ headphone=!(GPLR & GPIO_nREMOCON_INT);
- /* GPIO15:Falling Edge */
-- set_GPIO_IRQ_edge(GPIO_nREMOCON_INT, GPIO_FALLING_EDGE);
--
-+ set_GPIO_IRQ_edge(GPIO_nREMOCON_INT, GPIO_BOTH_EDGES);
- /* Register interrupt handler */
- if ( request_irq(IRQ_GPIO_nREMOCON_INT, Collie_rc_interrupt,
-- SA_INTERRUPT, "INSERT-HEADPHONE", Collie_rc_interrupt)) {
-- printk("%s: request_irq(%d) failed.\n",
-- __FUNCTION__, IRQ_GPIO_nREMOCON_INT);
-- }
-+ SA_INTERRUPT, "headphone", 0)) {
-+ printk("headphone: request_irq failed.\n");
-
-- /* Make threads */
-- kernel_thread(collie_audio_on, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
-+ }
-+ printk("Requested irq collie_rc succesfully (headphone) \n");
-+ printk("Headphone is now %s\n",headphone ? "connected" : "disconnected");
- #endif
-
--
-- LEAVE(TRACE_ON,"Collie_sound_init");
-+ Collie_audio_power_on(); // decreasing rec. noise?
-+ Collie_audio_power_off();
- return 0;
- }
-
--module_init(Collie_sound_init);
--
--
- #ifdef MODULE
--
--int init_module(void)
-+static int collie_ssp_init_module(void)
- {
-- ENTER(TRACE_ON,"init_module");
- Collie_sound_init();
-- LEAVE(TRACE_ON,"init_module");
- return 0;
- }
-
--void cleanup_module(void)
-+static void collie_ssp_cleanup_module(void)
- {
-- ENTER(TRACE_ON,"cleanup_module");
-+#ifdef CONFIG_PM
-+ pm_unregister(collie_sound_pm_dev);
-+#endif
- if (irq_installed) {
-- sound_silence();
-- sound.mach.irqcleanup();
-+ sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
-+ sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
-+ Collie_audio_power_off();
-+ sa1100_free_dma(COLLIE_SOUND_DMA_CHANNEL);
- }
--
-- sq_release_buffers();
--
-- if (mixer_unit >= 0)
-- unregister_sound_mixer(mixer_unit);
-- if (state_unit >= 0)
-- unregister_sound_special(state_unit);
-- if (sq_unit >= 0)
-- unregister_sound_dsp(sq_unit);
-- LEAVE(TRACE_ON,"cleanup_module");
--}
--
-+#ifdef COLLIE_TRY_ONE
-+ free_irq(IRQ_GPIO_nREMOCON_INT,0);
-+#endif
-+ unregister_sound_mixer(mixer_unit);
-+ unregister_sound_special(state_unit);
-+ unregister_sound_dsp(sq_unit);
-+ printk("collie_ssp has to go now, see you later!\n");
-+}
-+
-+module_init(collie_ssp_init_module);
-+module_exit(collie_ssp_cleanup_module);
-+MODULE_DESCRIPTION("Collie 16bit sound driver");
-+MODULE_AUTHOR("SHARP");
-+MODULE_LICENSE("GPL");
-+EXPORT_SYMBOL(Collie_recording_off);
-+EXPORT_SYMBOL(Collie_recording_on);
-+EXPORT_SYMBOL(collie_recording);
- #endif /* MODULE */
-+
-diff -Nuar linux-2.4.18/drivers/sound/collie_tc35143af.c linux-2.4.18p/drivers/sound/collie_tc35143af.c
---- linux-2.4.18/drivers/sound/collie_tc35143af.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.18p/drivers/sound/collie_tc35143af.c 2004-10-13 15:26:20.336631864 +0200
-@@ -0,0 +1,1457 @@
-+/*
-+ TODO
-+
-+ buzzer compatibility is not fool proof - if an app starts sending buzzer ioctls
-+ and then write or read, nothing good will happen / but this api is obsolote anyway
-+
-+ mixer_ioctls missing: write/read_mic/igain (there are sane defaults for those)
-+
-+ fixed samplerate at 22050hz (mono,s16_le), although it can be changed
-+ between 8000-22050hz hardwarewise
-+
-+
-+ DONE
-+
-+ buffers are only allocated once, and freed when module is unloaded
-+ mute left channel when duplex playing & recording
-+ cleanup
-+ depend on collie_ssp, and call needed functions when needed
-+ (recording noise should be gone too as a consequence)
-+ lineo's getospace incorporated (getispace left alone)
-+ "optimized" default fragsize and number, so there is now no clicking all the time
-+ commented out scndctl_dsp_setfragment so that no application can set bad settings (eg.xmms)
-+ if you start reading from this device, than it won't let you write later unless you close it first
-+ (and vica-versa)
-+ speaker is muted if nothing is playing, so noise is gone
-+
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/poll.h>
-+#include <linux/major.h>
-+#include <linux/config.h>
-+#include <linux/fcntl.h>
-+#include <linux/errno.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/sound.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+
-+#include <linux/pm.h>
-+
-+#include <asm/system.h>
-+#include <asm/irq.h>
-+#include <asm/pgtable.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/dma.h>
-+
-+#include <asm/ucb1200.h>
-+#include <linux/soundcard.h>
-+#include <asm/proc/cache.h>
-+
-+#include <asm/arch/hardware.h>
-+#include <asm/arch/tc35143.h>
-+
-+#undef DEBUG
-+#ifdef DEBUG
-+#define DPRINTK( x... ) printk( ##x )
-+#else
-+#define DPRINTK( x... )
-+#endif
-+
-+extern int collie_recording;
-+extern void Collie_recording_on(void);
-+extern void Collie_recording_off(void);
-+
-+int collie_tc35143f_irq = -1;
-+int collie_tc35143f_input_irq = -1;
-+
-+#define COLLIE_BUZZER_DMA_CHANNEL (collie_tc35143f_irq)
-+#define COLLIE_BUZZER_DMA_CHANNEL_INPUT (collie_tc35143f_input_irq)
-+#define COLLIE_GPIO_MIC GPIO_GPIO (17)
-+
-+#define SND_NDEVS 256 /* Number of supported devices */
-+#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-+#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */
-+#define SND_DEV_MIDIN 2 /* Raw midi access */
-+#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-+#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-+#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-+#define SND_DEV_STATUS 6 /* /dev/sndstat */
-+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-+#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-+#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-+#define SND_DEV_PSS SND_DEV_SNDPROC
-+
-+#ifdef MODULE
-+static int sq_unit = -1;
-+static int mixer_unit = -1;
-+static int state_unit = -1;
-+static int irq_installed = 0;
-+#endif /* MODULE */
-+
-+#ifdef CONFIG_PM
-+static struct pm_dev* collie_sound_pm_dev;
-+#endif
-+
-+/*** Some declarations ***********************************************/
-+static int collie_buzzer_volume = 100;
-+static int audio_igain = 0;
-+static int audio_iamp = 0x05;
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+static struct ucb1x00 * ucbstruct;
-+#endif
-+static int TC35143f_control_reg_a;
-+static int TC35143f_control_reg_b;
-+static int TC35143f_mode;
-+
-+#define AUDIO_NBFRAGS_DEFAULT 32
-+#define AUDIO_FRAGSIZE_DEFAULT 2048
-+
-+typedef struct {
-+ int size; /* buffer size */
-+ char *start; /* points to actual buffer */
-+ dma_addr_t dma_addr; /* physical buffer address */
-+ struct semaphore sem; /* down before touching the buffer */
-+ int master; /* master owner for buffer allocation */
-+ u_int idx; /* buffer index, so that we know which buffer was sent last*/
-+} audio_buf_t;
-+
-+typedef struct {
-+ audio_buf_t *buffers; /* pointer to audio buffer structures */
-+ audio_buf_t *buf; /* current buffer used by read/write */
-+ u_int buf_idx; /* index for the pointer above... */
-+ u_int fragsize; /* fragment i.e. buffer size */
-+ u_int nbfrags; /* nbr of fragments i.e. buffers */
-+} audio_stream_t;
-+
-+static audio_stream_t output_stream, input_stream;
-+
-+#define NEXT_BUF(_s_,_b_) { \
-+ (_s_)->_b_##_idx++; \
-+ (_s_)->_b_##_idx %= (_s_)->nbfrags; \
-+ (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }
-+
-+/* Current specs for incoming audio data */
-+static u_int audio_fragsize=AUDIO_FRAGSIZE_DEFAULT;
-+static u_int audio_nbfrags=AUDIO_NBFRAGS_DEFAULT;
-+
-+static volatile int audio_refcount; /* nbr of concurrent open() for playback */
-+typedef enum { REC,PLAY,NA,BUZZ } collie_tc_status_t;
-+static collie_tc_status_t collie_tc_status;
-+int collie_tc_muted;
-+
-+#define IOCTL_IN(arg, ret) \
-+ do { int error = get_user(ret, (int *)(arg)); \
-+ if (error) return error; \
-+ } while (0)
-+#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-+
-+/*** "Translations" ************************************************************/
-+
-+static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
-+ u_char frame[], ssize_t *frameUsed,
-+ ssize_t frameLeft);
-+static signed short ct_out=0;
-+/*** Low level stuff *********************************************************/
-+
-+
-+typedef struct {
-+ int format; /* AFMT_* */
-+ int stereo; /* 0 = mono, 1 = stereo */
-+ int size; /* 8/16 bit*/
-+ int speed; /* speed */
-+ int volume;
-+} SETTINGS;
-+
-+static SETTINGS sound;
-+
-+#ifdef CONFIG_PM
-+//extern int autoPowerCancel;
-+#endif
-+
-+static void Collie_Set_Volume(int volume);
-+static int Collie_Get_Volume(void);
-+static int CollieIrqInit(void);
-+static int CollieSetFormat(int format);
-+static void Collie_sq_interrupt(void*, int);
-+static int sq_allocate_buffers(audio_stream_t*);
-+static void sq_release_buffers(audio_stream_t*);
-+
-+/*** Mid level stuff *********************************************************/
-+static int sound_set_speed(int speed);
-+
-+/*
-+ * /dev/mixer abstraction
-+ */
-+
-+struct sound_mixer {
-+ int busy;
-+};
-+
-+static struct sound_mixer mixer;
-+
-+/*
-+ * /dev/sndstat
-+ */
-+
-+/*** Common stuff ********************************************************/
-+
-+static long long sound_lseek(struct file *file, long long offset, int orig);
-+static inline int ioctl_return(int *addr, int value)
-+{
-+ if (value < 0) {
-+ return(value);
-+ }
-+ return put_user(value, addr)? -EFAULT: 0;
-+}
-+
-+static void wait_ms(int ten_ms)
-+{
-+ schedule_timeout(ten_ms);
-+}
-+
-+/*** Translation ************************************************************/
-+
-+static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
-+ u_char frame[], ssize_t *frameUsed,
-+ ssize_t frameLeft)
-+{
-+ ssize_t count, used;
-+ signed short *fp = (unsigned short *) &frame[*frameUsed];
-+ signed short *up = (unsigned short *) userPtr;
-+
-+ frameLeft >>= 1;
-+ userCount >>= 1;
-+ used = count = (userCount < frameLeft) ? userCount : frameLeft;
-+
-+ while (count > 0) {
-+ signed short data;
-+ if (get_user(data, up++)) {
-+ return -EFAULT;
-+ } /* lowpass filtering, not that it matters much - something is resonating inside the Zaurus at high frequencies ? */
-+ *fp++ = ct_out = (short)( ( (long)data + (long)ct_out ) >> 1LL );
-+ count--;
-+ }
-+
-+ *frameUsed += used * 2;
-+ return used * 2;
-+}
-+
-+/*** HARDWARE dependent stuff *********************************************************/
-+#define VOL_THRES 10
-+#define CODEC_ASD_NUMERATOR 13
-+/*~ (9216000 / ( 32 * 22050 )) */
-+
-+static int Collie_Sampling_value(void)
-+{
-+ int asd = CODEC_ASD_NUMERATOR;
-+ DPRINTK("Collie_Sampling_value %x\n",asd);
-+ return asd;
-+}
-+
-+static void Collie_sound_hard_init(void)
-+{
-+ int asd;
-+
-+ DPRINTK("CollieInit\n");
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_enable(ucbstruct);
-+ ucb1x00_io_set_dir(ucbstruct,0, TC35143_GPIO_BUZZER_BIAS);
-+ ucb1x00_disable(ucbstruct);
-+#else
-+ ucb1200_set_io_direction(TC35143_GPIO_BUZZER_BIAS, TC35143_IODIR_OUTPUT);
-+#endif
-+
-+ DPRINTK("TC35143F Init");
-+
-+ // init MCP
-+ asd = Collie_Sampling_value();
-+ Ser4MCCR0 &= ~MCCR0_MCE;
-+ Ser4MCCR0 &= ~0xff;
-+ Ser4MCCR0 |= (MCCR0_ARE | MCCR0_ATE |MCCR0_ADM | MCCR0_ECS | asd);
-+ Ser4MCCR0 |= MCCR0_MCE;
-+ Ser4MCSR = 0xffffffff;
-+
-+ DPRINTK("Init MCP %x\n",Ser4MCCR0);
-+}
-+
-+static void Collie_audio_power_on(void)
-+{
-+ if ( collie_buzzer_volume > 100 ) collie_buzzer_volume = 100;
-+ if ( collie_buzzer_volume < 0 ) collie_buzzer_volume = 0;
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_enable(ucbstruct);
-+#endif
-+ TC35143f_control_reg_a = ( TC35143_VDIV_22KHZ );
-+ TC35143f_control_reg_b = ( TC35143_VADMUTE | TC35143_VHSMUTE | ( 7 - collie_buzzer_volume / 13));
-+ TC35143f_mode = ( TC35143_VOFFCAN | TC35143_VCOF_22_OR_16KHZ );
-+ TC35143f_control_reg_a &= ~(TC35143_VINSEL_MASK | TC35143_VGAIN_MASK | TC35143_VAMP_MASK);
-+ TC35143f_control_reg_a |= (TC35143_VINSEL_VBIN2 | ((audio_igain & 0x3)<<11) | ((audio_iamp & 0x0f)<<7));
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B , TC35143f_control_reg_b);
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A , TC35143f_control_reg_a);
-+ ucb1x00_reg_write(ucbstruct,TC35143_MODE_REG , TC35143f_mode );
-+ ucb1x00_io_write(ucbstruct, TC35143_GPIO_BUZZER_BIAS,0);
-+ ucb1x00_disable(ucbstruct);
-+#else
-+ ucb1200_write_reg(TC35143_CONTROL_REG_B , TC35143f_control_reg_b );
-+ ucb1200_write_reg(TC35143_MODE_REG , TC35143f_mode );
-+ ucb1200_write_reg(TC35143_CONTROL_REG_A , TC35143f_control_reg_a );
-+ ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_HIGH);
-+#endif
-+ collie_tc_muted=1;
-+}
-+
-+static void Collie_audio_power_off(void){ /* Disable sound only */
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_enable(ucbstruct);
-+ ucb1x00_io_write(ucbstruct,0, TC35143_GPIO_BUZZER_BIAS);
-+#else
-+ ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_LOW);
-+#endif
-+
-+ TC35143f_control_reg_a = ( TC35143_VDIV_22KHZ );
-+ TC35143f_control_reg_b = ( TC35143_ALL_MUTE );
-+
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B , TC35143f_control_reg_b);
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A , TC35143f_control_reg_a);
-+ ucb1x00_disable(ucbstruct);
-+#else
-+ ucb1200_write_reg(TC35143_CONTROL_REG_B , TC35143f_control_reg_b );
-+ ucb1200_write_reg(TC35143_CONTROL_REG_A , TC35143f_control_reg_a );
-+#endif
-+}
-+
-+static void collie_tc_mute_on(void){
-+ unsigned int reg_b;
-+ unsigned int reg_a;
-+
-+ if (!collie_tc_muted) {
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_enable(ucbstruct);
-+ reg_b = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B);
-+ reg_a = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_A);
-+#else
-+ reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B);
-+ reg_a = ucb1200_read_reg(TC35143_CONTROL_REG_A);
-+#endif
-+ reg_b &= ~TC35143_VOUT1_EN;
-+ reg_a &= ~TC35143_VOUT2_EN;
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A, reg_a);
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b);
-+ ucb1x00_disable(ucbstruct);
-+#else
-+ ucb1200_write_reg(TC35143_CONTROL_REG_A, reg_a);
-+ ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
-+#endif
-+ collie_tc_muted=1;
-+ }
-+}
-+
-+static void collie_tc_mute_off(void){
-+ unsigned int reg_b;
-+ unsigned int reg_a;
-+
-+ if (collie_tc_muted) {
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_enable(ucbstruct);
-+ reg_b = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B);
-+ reg_a = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_A);
-+#else
-+ reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B);
-+ reg_a = ucb1200_read_reg(TC35143_CONTROL_REG_A);
-+#endif
-+ reg_b |= TC35143_VOUT1_EN ;
-+ reg_b &= ~7;
-+ reg_b |= ( 7 - collie_buzzer_volume / 13);
-+ reg_a |= TC35143_VOUT2_EN;
-+ reg_a &= ~(TC35143_VGAIN_MASK | TC35143_VAMP_MASK);
-+ reg_a |= (((audio_igain & 0x3)<<11) | ((audio_iamp & 0x0f)<<7));
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A, reg_a);
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b);
-+ ucb1x00_disable(ucbstruct);
-+#else
-+ ucb1200_write_reg(TC35143_CONTROL_REG_A, reg_a);
-+ ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
-+#endif
-+ collie_tc_muted=0;
-+ }
-+}
-+
-+
-+static void Collie_volume_set(int dest)
-+{
-+ if (collie_buzzer_volume==dest) return;
-+ collie_buzzer_volume=dest;
-+ collie_tc_mute_on();
-+ collie_tc_mute_off();
-+}
-+
-+
-+/*********** GENERAL stuff, same as collie_ssp *******************************/
-+
-+
-+static void Collie_Set_Volume(int volume)
-+{
-+ sound.volume = volume & 0xff;
-+ sound.volume += ( volume & 0xff00 >> 8);
-+ sound.volume >>=1;
-+ if (sound.volume>100) sound.volume=100;
-+}
-+
-+static int Collie_Get_Volume(void)
-+{
-+ return ( sound.volume << 8 | sound.volume );
-+}
-+
-+static void Collie_sq_interrupt(void* id, int size)
-+{
-+ audio_buf_t *b = (audio_buf_t *) id;
-+ audio_buf_t *b2 = output_stream.buffers + ((b->idx + 1) % output_stream.nbfrags);
-+
-+ /* If this is the last buffer for know, let's mute the speaker */
-+ if (!down_trylock(&b2->sem)) {
-+ collie_tc_mute_on();
-+ up(&b2->sem);
-+ }
-+
-+ /*
-+ * Current buffer is sent: wake up any process waiting for it.
-+ */
-+ up(&b->sem);
-+ /* And any process polling on write. */
-+ wake_up_interruptible(&b->sem.wait);
-+
-+ DPRINTK("Collie_sq_interrupt \n");
-+}
-+
-+static void Collie_sq_input_interrupt(void* id, int size)
-+{
-+ audio_buf_t *b = (audio_buf_t *) id;
-+ /*
-+ * Current buffer is sent: wake up any process waiting for it.
-+ */
-+ b->size = size;
-+ up(&b->sem);
-+ /* And any process polling on write. */
-+ wake_up_interruptible(&b->sem.wait);
-+ /* And indicate which was the last buffer sent */
-+
-+ DPRINTK("Collie_sq_input_interrupt \n");
-+}
-+
-+
-+static int __init CollieIrqInit(void)
-+{
-+ int err;
-+
-+ err = sa1100_request_dma(&COLLIE_BUZZER_DMA_CHANNEL, "buzzer output",
-+ DMA_Ser4MCP0Wr);
-+
-+ if (err) {
-+ return 0;
-+ }
-+ printk("collie_tc35143f_irq=%d\n", collie_tc35143f_irq);
-+
-+ err = sa1100_request_dma(&COLLIE_BUZZER_DMA_CHANNEL_INPUT, "buzzer input",
-+ DMA_Ser4MCP0Rd);
-+
-+ if (err) {
-+ return 0;
-+ }
-+ printk("collie_tc35143f_input_irq=%d\n", collie_tc35143f_input_irq);
-+
-+
-+ sa1100_dma_set_callback(COLLIE_BUZZER_DMA_CHANNEL,
-+ (dma_callback_t)Collie_sq_interrupt);
-+
-+ sa1100_dma_set_callback(COLLIE_BUZZER_DMA_CHANNEL_INPUT,
-+ (dma_callback_t)Collie_sq_input_interrupt);
-+
-+
-+ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL);
-+ Collie_audio_power_off();
-+ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL);
-+ return(1);
-+}
-+
-+static int CollieSetFormat(int format)
-+{
-+ int size;
-+
-+ switch (format) {
-+ case AFMT_QUERY:
-+ return(sound.format);
-+ default: /* This is the only one supported by the hardware it seems */
-+ size = 16;
-+ format = AFMT_S16_LE;
-+ }
-+ sound.format = format;
-+ sound.size = size;
-+
-+ return(format);
-+}
-+
-+
-+static int sound_set_speed(int speed)
-+{
-+ if (speed < 0) {
-+ return(sound.speed);
-+ }
-+ sound.speed=22050;
-+ return(sound.speed);
-+}
-+
-+/* Higher level stuff ************************************************/
-+
-+/*
-+ * /dev/mixer abstraction
-+ */
-+
-+static int mixer_open(struct inode *inode, struct file *file)
-+{
-+ MOD_INC_USE_COUNT;
-+ mixer.busy = 1;
-+ return 0;
-+}
-+
-+static int mixer_release(struct inode *inode, struct file *file)
-+{
-+ mixer.busy = 0;
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+
-+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-+ u_long arg)
-+{
-+ int data;
-+
-+ DPRINTK("Got mixer ioctl \n");
-+
-+ switch (cmd) {
-+ case SOUND_MIXER_INFO:
-+ DPRINTK("0\n");
-+ return 0;
-+ case SOUND_OLD_MIXER_INFO:
-+ DPRINTK("0\n");
-+ return 0;
-+
-+ case SOUND_MIXER_READ_DEVMASK:
-+ DPRINTK("1\n");
-+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_IGAIN );
-+ case SOUND_MIXER_READ_RECMASK:
-+ DPRINTK("2\n");
-+ return IOCTL_OUT(arg, SOUND_MASK_MIC);
-+ case SOUND_MIXER_READ_STEREODEVS:
-+ DPRINTK("3\n");
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_READ_CAPS:
-+ DPRINTK("4\n");
-+ return IOCTL_OUT(arg, 0);
-+
-+ case SOUND_MIXER_WRITE_VOLUME:
-+ IOCTL_IN(arg, data);
-+ Collie_Set_Volume(data);
-+ DPRINTK("mix_io returning\n");
-+ return IOCTL_OUT(arg, data);
-+ case SOUND_MIXER_READ_VOLUME:
-+ DPRINTK("5\n");
-+ return IOCTL_OUT(arg, Collie_Get_Volume());
-+ case SOUND_MIXER_READ_TREBLE:
-+ DPRINTK("6\n");
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_WRITE_TREBLE:
-+ DPRINTK("7\n");
-+ return IOCTL_OUT(arg, 0);
-+
-+ case SOUND_MIXER_READ_BASS:
-+ DPRINTK("6b\n");
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_WRITE_BASS:
-+ DPRINTK("7b\n");
-+ return IOCTL_OUT(arg, 0);
-+
-+
-+ case SOUND_MIXER_WRITE_MIC:
-+ case SOUND_MIXER_WRITE_IGAIN:
-+ DPRINTK("8\n");
-+ return IOCTL_OUT(arg, 100);
-+ case SOUND_MIXER_READ_MIC:
-+ case SOUND_MIXER_READ_IGAIN:
-+ DPRINTK("9\n");
-+ return IOCTL_OUT(arg, 0);
-+
-+ case SOUND_MIXER_READ_SPEAKER:
-+ DPRINTK("10\n");
-+ return IOCTL_OUT(arg, 0);
-+ case SOUND_MIXER_WRITE_SPEAKER:
-+ DPRINTK("11\n");
-+ return IOCTL_OUT(arg, 0);
-+ default:
-+ DPRINTK("12 %d\n",cmd);
-+ return -ENOSYS;
-+ }
-+ DPRINTK("EINVAL %d??\n",cmd);
-+ return -EINVAL;
-+}
-+
-+
-+static struct file_operations mixer_fops =
-+{
-+ llseek: sound_lseek,
-+ ioctl: mixer_ioctl,
-+ open: mixer_open,
-+ release: mixer_release,
-+};
-+
-+
-+static void __init mixer_init(void)
-+{
-+ mixer_unit = register_sound_mixer(&mixer_fops, -1);
-+ if (mixer_unit < 0) {
-+ return;
-+ }
-+ mixer.busy = 0;
-+ sound.volume = 100;
-+ Collie_volume_set(sound.volume);
-+}
-+
-+/* This function initializes the buffer
-+ */
-+
-+static void sq_clean_buffers(audio_stream_t * s)
-+{
-+ int frag;
-+
-+ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+
-+ s->nbfrags = audio_nbfrags;
-+ s->fragsize = audio_fragsize;
-+
-+ if (!s->buffers)
-+ goto err;
-+
-+ for (frag = 0; frag < s->nbfrags; frag++) {
-+ audio_buf_t *b = &s->buffers[frag];
-+ b->size=0;
-+ sema_init(&b->sem, 1);
-+ }
-+ s->buf_idx = 0;
-+ s->buf = &s->buffers[0];
-+ return;
-+
-+err:
-+ printk("sound driver : where did the buffer go ??\n ");
-+}
-+
-+/* This function allocates the buffer structure array and buffer data space
-+ * according to the current number of fragments and fragment size.
-+ */
-+
-+static int sq_allocate_buffers(audio_stream_t * s)
-+{
-+ int frag;
-+ int dmasize = 0;
-+ char *dmabuf = 0;
-+ dma_addr_t dmaphys = 0;
-+
-+ DPRINTK("sq_allocate_buffers\n");
-+
-+ if (s->buffers) {
-+ return -EBUSY;
-+ }
-+
-+ s->nbfrags = audio_nbfrags;
-+ s->fragsize = audio_fragsize;
-+
-+ s->buffers = (audio_buf_t *)
-+ kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
-+ if (!s->buffers)
-+ goto err;
-+ memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
-+
-+ for (frag = 0; frag < s->nbfrags; frag++) {
-+ audio_buf_t *b = &s->buffers[frag];
-+
-+ /*
-+ * Let's allocate non-cached memory for DMA buffers.
-+ * We try to allocate all memory at once.
-+ * If this fails (a common reason is memory fragmentation),
-+ * then we allocate more smaller buffers.
-+ */
-+ if (!dmasize) {
-+ dmasize = (s->nbfrags - frag) * s->fragsize;
-+ do {
-+ dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA,
-+ dmasize,
-+ &dmaphys);
-+ if (!dmabuf)
-+ dmasize -= s->fragsize;
-+ } while (!dmabuf && dmasize);
-+ if (!dmabuf)
-+ goto err;
-+ b->master = dmasize;
-+ }
-+
-+ b->start = dmabuf;
-+ b->dma_addr = dmaphys;
-+ b->idx = frag;
-+ sema_init(&b->sem, 1);
-+ dmabuf += s->fragsize;
-+ dmaphys += s->fragsize;
-+ dmasize -= s->fragsize;
-+ }
-+
-+ s->buf_idx = 0;
-+ s->buf = &s->buffers[0];
-+
-+ return 0;
-+
-+err:
-+ printk("sound driver : unable to allocate audio memory\n ");
-+ sq_release_buffers(s);
-+ return -ENOMEM;
-+}
-+
-+/*
-+ * This function frees all buffers
-+ */
-+
-+static void sq_release_buffers(audio_stream_t * s)
-+{
-+ DPRINTK("sq_release_buffers\n");
-+
-+ /* ensure DMA won't run anymore */
-+ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+
-+ if (s->buffers) {
-+ int frag;
-+ for (frag = 0; frag < s->nbfrags; frag++) {
-+ if (!s->buffers[frag].master)
-+ continue;
-+ consistent_free(s->buffers[frag].start,
-+ s->buffers[frag].master,
-+ s->buffers[frag].dma_addr);
-+ }
-+ kfree(s->buffers);
-+ s->buffers = NULL;
-+ }
-+
-+ s->buf_idx = 0;
-+ s->buf = NULL;
-+}
-+
-+static int audio_recording(audio_stream_t * s)
-+{
-+ int i;
-+ unsigned int reg_b;
-+
-+ if (!collie_recording) {
-+ /*
-+ * Set TC35143 Audio in enable
-+ */
-+//// DPRINTK("audio_recording : audio in enable\n");
-+//// reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B);
-+//// reg_b &= ~(TC35143_VADMUTE);
-+//// reg_b |= (TC35143_VIN_EN | TC35143_VCLP_CLR);
-+//// ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
-+
-+ /*
-+ * We must ensure there is an output stream at any time while
-+ * recording since this is how the TC35143 gets its clock.
-+ * So if there is no playback data to send, the output DMA will
-+ * spin with all zeroes.
-+ */
-+
-+ Collie_recording_on();
-+ collie_tc_mute_off(); /* This is needed for good volume */
-+ DPRINTK("audio_recording : sa1100_dma_set_spin\n");
-+ sa1100_dma_set_spin(COLLIE_BUZZER_DMA_CHANNEL,
-+ (dma_addr_t) FLUSH_BASE_PHYS, 2048);
-+
-+ /*
-+ * Since we just allocated all buffers, we must send them to
-+ * the DMA code before receiving data.
-+ */
-+ DPRINTK("audio_recording : for loop\n");
-+ for (i = 0; i < s->nbfrags; i++) {
-+ audio_buf_t *b = s->buf;
-+ down(&b->sem);
-+ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL_INPUT, (void *) b,
-+ b->dma_addr, s->fragsize);
-+ NEXT_BUF(s, buf);
-+ }
-+ DPRINTK("audio_recording : End for loop\n");
-+
-+ /*
-+ * Set TC35143 Audio in enable
-+ */
-+ DPRINTK("audio_recording : audio in enable\n");
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_enable(ucbstruct);
-+ ucb1x00_io_write(ucbstruct, 0, TC35143_GPIO_BUZZER_BIAS);
-+ reg_b = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B);
-+#else
-+ ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_LOW);
-+ reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B);
-+#endif
-+ reg_b &= ~(TC35143_VADMUTE);
-+ reg_b |= (TC35143_VIN_EN | TC35143_VCLP_CLR);
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b);
-+ ucb1x00_disable(ucbstruct);
-+#else
-+ ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
-+#endif
-+ }
-+ return 0;
-+}
-+
-+
-+static int sq_read(struct file *file, char *buffer,
-+ size_t count, loff_t * ppos)
-+{
-+ char *buffer0 = buffer;
-+ audio_stream_t *s = &input_stream;
-+ int chunksize, ret = 0;
-+
-+ DPRINTK("audio_read: count=%d\n", count);
-+
-+
-+ ret = audio_recording(s);
-+
-+ if ((collie_tc_status!=NA) && (collie_tc_status!=REC))
-+ return -EPERM;
-+ collie_tc_status=REC;
-+
-+ if (ret)
-+ return ret;
-+
-+ /* be sure to have a full sample byte count */
-+ count &= ~0x03;
-+
-+// DPRINTK("audio_read : Start while loop\n");
-+ while (count > 0) {
-+ audio_buf_t *b = s->buf;
-+
-+ /* Wait for a buffer to become full */
-+ if (file->f_flags & O_NONBLOCK) {
-+// DPRINTK("audio_read : down_trylock\n");
-+ ret = -EAGAIN;
-+ if (down_trylock(&b->sem))
-+ break;
-+ } else {
-+// DPRINTK("audio_read : down_interruptible\n");
-+ ret = -ERESTARTSYS;
-+ if (down_interruptible(&b->sem))
-+ break;
-+ }
-+
-+ /* Grab data from the current buffer */
-+ chunksize = b->size;
-+ if (chunksize > count)
-+ chunksize = count;
-+ DPRINTK("read %d from %d\n", chunksize, s->buf_idx);
-+
-+ if (copy_to_user(buffer, b->start + s->fragsize - b->size, chunksize)) {
-+ up(&b->sem);
-+ DPRINTK("not copied to buffer \n");
-+ return -EFAULT;
-+ }
-+ DPRINTK("copied to buffer \n");
-+
-+ b->size -= chunksize;
-+ buffer += chunksize;
-+ count -= chunksize;
-+
-+ if (b->size > 0) {
-+ up(&b->sem);
-+ break;
-+ }
-+
-+ /* Make current buffer available for DMA again */
-+ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL_INPUT, (void *) b,
-+ b->dma_addr, s->fragsize);
-+ NEXT_BUF(s, buf);
-+ }
-+// DPRINTK("audio_read : End while loop\n");
-+
-+ if ((buffer - buffer0))
-+ ret = buffer - buffer0;
-+// DPRINTK("audio_read: return=%d\n", ret);
-+ return ret;
-+}
-+
-+static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
-+ loff_t *ppos)
-+{
-+ const char *buffer0 = src;
-+ audio_stream_t *s = &output_stream;
-+ u_char *dest;
-+ ssize_t uUsed, bUsed, bLeft, ret = 0;
-+
-+ DPRINTK("sq_write: uLeft=%d\n", uLeft);
-+
-+ if ((collie_tc_status!=NA) && (collie_tc_status!=PLAY))
-+ return -EPERM;
-+
-+ collie_tc_status=PLAY;
-+
-+ if (!s->buffers && sq_allocate_buffers(s)) {
-+ return -ENOMEM;
-+ }
-+
-+
-+#ifdef CONFIG_PM
-+ /* Auto Power off cancel */
-+// autoPowerCancel = 0;
-+#endif
-+
-+ collie_tc_mute_off();
-+ while (uLeft > 0) {
-+ audio_buf_t *b = s->buf;
-+
-+ /* Wait for a buffer to become free */
-+ if (file->f_flags & O_NONBLOCK) {
-+ ret = -EAGAIN;
-+ if (down_trylock(&b->sem)) {
-+ break;
-+ }
-+ } else {
-+ ret = -ERESTARTSYS;
-+ if (down_interruptible(&b->sem)) {
-+ break;
-+ }
-+ }
-+
-+ dest = b->start + b->size;
-+ bUsed = 0;
-+ bLeft = s->fragsize - b->size;
-+
-+ if (collie_ct_s16) {
-+ uUsed = collie_ct_s16(src, uLeft, dest, &bUsed, bLeft);
-+ cpu_cache_clean_invalidate_range((unsigned long)dest,
-+ (unsigned long)(dest+(audio_fragsize)), 0);
-+ } else {
-+ return -EFAULT;
-+ }
-+
-+ if (uUsed < 0) {
-+ up(&b->sem);
-+ return -EFAULT;
-+ }
-+ src += uUsed;
-+ uLeft -= uUsed;
-+ b->size += bUsed;
-+
-+ if (b->size < s->fragsize) {
-+ up(&b->sem);
-+ break;
-+ }
-+
-+ /* Send current buffer to dma */
-+ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
-+ (void *) b, b->dma_addr, b->size);
-+
-+ Collie_volume_set(sound.volume);
-+
-+ b->size = 0; /* indicate that the buffer has been sent */
-+ NEXT_BUF(s, buf);
-+ }
-+
-+ if ((src - buffer0))
-+ ret = src - buffer0;
-+ DPRINTK("sq_write: return=%d\n", ret);
-+ return ret;
-+}
-+
-+static unsigned int sq_poll(struct file *file,
-+ struct poll_table_struct *wait)
-+{
-+ unsigned int mask = 0;
-+ int i,ret;
-+
-+ DPRINTK("sq_poll(): mode=%s%s\n",
-+ (file->f_mode & FMODE_READ) ? "r" : "",
-+ (file->f_mode & FMODE_WRITE) ? "w" : "");
-+
-+ if ((file->f_mode & FMODE_READ) && (file->f_mode & FMODE_WRITE) && (collie_tc_status==NA))
-+ return mask;
-+
-+ if ((file->f_mode & FMODE_WRITE) && (collie_tc_status!=REC)) {
-+ if (!output_stream.buffers
-+ && sq_allocate_buffers(&output_stream)) {
-+ return -ENOMEM;
-+ }
-+ poll_wait(file, &output_stream.buf->sem.wait, wait);
-+ }
-+
-+ if ((file->f_mode & FMODE_WRITE) && (collie_tc_status!=REC)) {
-+ for (i = 0; i < output_stream.nbfrags; i++) {
-+ if (atomic_read(&output_stream.buffers[i].sem.count) > 0)
-+ mask |= POLLOUT | POLLWRNORM;
-+ }
-+ }
-+
-+ if ((file->f_mode & FMODE_READ) && (collie_tc_status!=PLAY)) {
-+ ret = audio_recording(&input_stream);
-+ if (ret<0) {
-+ return ret;
-+ }
-+ poll_wait(file, &input_stream.buf->sem.wait, wait);
-+ }
-+
-+ if ((file->f_mode & FMODE_READ) && (collie_tc_status!=PLAY)) {
-+ for (i = 0; i < input_stream.nbfrags; i++) {
-+ if (atomic_read(&input_stream.buffers[i].sem.count) > 0)
-+ mask |= POLLIN | POLLRDNORM;
-+ }
-+ }
-+
-+ DPRINTK("sq_poll() returned mask of %s%s\n",
-+ (mask & POLLIN) ? "r" : "",
-+ (mask & POLLOUT) ? "w" : "");
-+
-+ return mask;
-+}
-+
-+static int sq_open(struct inode *inode, struct file *file)
-+{
-+ DPRINTK("sq_open\n");
-+
-+ if (audio_refcount) {
-+ DPRINTK(" sq_open EBUSY\n");
-+ return -EBUSY;
-+ }
-+
-+ switch (file->f_flags & O_ACCMODE) {
-+ case O_WRONLY:
-+ collie_tc_status=PLAY;
-+ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ break;
-+ case O_RDONLY:
-+ collie_tc_status=REC;
-+ break;
-+ case O_RDWR:
-+ collie_tc_status=NA;
-+ break;
-+ default:
-+ DPRINTK(" sq_open EINVAL\n");
-+ return -EINVAL;
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+ audio_refcount++;
-+
-+ audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
-+ audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
-+ sq_clean_buffers(&input_stream);
-+ sq_clean_buffers(&output_stream);
-+ Collie_audio_power_on();
-+ DPRINTK("Going back\n");
-+ return 0;
-+}
-+
-+static int sq_post(void)
-+{
-+ audio_stream_t *s = &output_stream;
-+ audio_buf_t *b = s->buf;
-+
-+ DPRINTK("sq_post\n");
-+
-+ if (!s->buffers) {
-+ return 0;
-+ }
-+
-+ /* Send half-full buffers */
-+ if (b->size != 0) {
-+ DPRINTK("half-full_buf\n");
-+
-+#ifdef CONFIG_PM
-+ /* Auto Power off cancel */
-+// autoPowerCancel = 0;
-+#endif
-+
-+ down(&b->sem);
-+ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
-+ (void *) b, b->dma_addr, b->size);
-+ b->size = 0;
-+ NEXT_BUF(s, buf);
-+ }
-+ return 0;
-+}
-+
-+static int sq_fsync(void)
-+{
-+ audio_stream_t *s = &output_stream;
-+ audio_buf_t *b = s->buf;
-+
-+ DPRINTK("sq_fsync\n");
-+
-+ if (!s->buffers) {
-+ return 0;
-+ }
-+
-+ /* Send half-full buffers */
-+ if (b->size != 0) {
-+ DPRINTK("half-full_buf\n");
-+
-+#ifdef CONFIG_PM
-+ /* Auto Power off cancel */
-+// autoPowerCancel = 0;
-+#endif
-+
-+ down(&b->sem);
-+ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
-+ (void *) b, b->dma_addr, b->size);
-+ b->size = 0;
-+ NEXT_BUF(s, buf);
-+ }
-+
-+ /*
-+ * Let's wait for the last buffer we sent i.e. the one before the
-+ * current buf_idx. When we acquire the semaphore, this means either:
-+ * - DMA on the buffer completed or
-+ * - the buffer was already free thus nothing else to sync.
-+ */
-+ b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags);
-+ if (down_interruptible(&b->sem)) {
-+ return -EINTR;
-+ }
-+ up(&b->sem);
-+ return 0;
-+}
-+
-+static int sq_release(struct inode *inode, struct file *file)
-+{
-+ DPRINTK("speaker_sq_release\n");
-+
-+ switch (collie_tc_status) {
-+
-+ case REC:
-+ sa1100_dma_set_spin(COLLIE_BUZZER_DMA_CHANNEL,0,0);
-+ sq_clean_buffers(&input_stream);
-+ Collie_recording_off();
-+ break;
-+ case PLAY:
-+ sq_fsync();
-+ sq_clean_buffers(&output_stream);
-+ break;
-+ default:
-+ break;
-+ }
-+ audio_refcount = 0;
-+ collie_tc_status=NA;
-+ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL);
-+ Collie_audio_power_off();
-+ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+/* Buzzer compatibility */
-+#include "colliebuzzer.h"
-+
-+
-+static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
-+ u_long arg)
-+{
-+ u_long fmt;
-+ int data,ret;
-+// audio_buf_info abinfo;
-+
-+ DPRINTK("Got ioctl %ld \n",cmd);
-+
-+ switch (cmd) {
-+ case 22144:
-+ sq_write_buzzer(arg);
-+ sq_fsync();
-+ return 0;
-+ case SNDCTL_DSP_RESET:
-+ switch (collie_tc_status) {
-+ case REC:
-+ sq_clean_buffers(&input_stream);
-+ case PLAY:
-+ sq_fsync();
-+ sq_clean_buffers(&output_stream);
-+ default:
-+ break;
-+ }
-+ return 0;
-+ case SNDCTL_DSP_POST:
-+ sq_post();
-+ return 0;
-+ case SNDCTL_DSP_SYNC:
-+ sq_fsync();
-+ return 0;
-+
-+ /* ++TeSche: before changing any of these it's
-+ * probably wise to wait until sound playing has
-+ * settled down. */
-+ case SNDCTL_DSP_SPEED:
-+// sq_fsync(file, file->f_dentry);
-+ IOCTL_IN(arg, data);
-+ return IOCTL_OUT(arg, sound_set_speed(data));
-+
-+ case SOUND_PCM_READ_RATE:
-+ return 0;
-+
-+ case SNDCTL_DSP_STEREO:
-+// sq_fsync(file, file->f_dentry);
-+ IOCTL_IN(arg, data);
-+ return IOCTL_OUT(arg, 0);
-+ case SNDCTL_DSP_CHANNELS:
-+// sq_fsync(file, file->f_dentry);
-+ IOCTL_IN(arg, data);
-+ return IOCTL_OUT(arg, 1);
-+ case SNDCTL_DSP_SETFMT:
-+// sq_fsync(file, file->f_dentry);
-+ IOCTL_IN(arg, data);
-+ return IOCTL_OUT(arg, CollieSetFormat(data));
-+ case SNDCTL_DSP_GETFMTS:
-+ fmt = AFMT_S16_LE;
-+ return IOCTL_OUT(arg, fmt);
-+ case SNDCTL_DSP_GETBLKSIZE:
-+ return IOCTL_OUT(arg, audio_fragsize);
-+ case SNDCTL_DSP_SUBDIVIDE:
-+ break;
-+ case SNDCTL_DSP_SETFRAGMENT:
-+/* if (output_stream.buffers) {
-+ return -EBUSY;
-+ }
-+ get_user(val, (long *) arg);
-+ audio_fragsize = 1 << (val & 0xFFFF);
-+ if (audio_fragsize < 256)
-+ audio_fragsize = 256;
-+ if (audio_fragsize > 16384)
-+ audio_fragsize = 16384;
-+ audio_nbfrags = (val >> 16) & 0x7FFF;
-+ if (audio_nbfrags < 2)
-+ audio_nbfrags = 2;
-+ if (audio_nbfrags * audio_fragsize > 128 * 1024)
-+ audio_nbfrags = 128 * 1024 / audio_fragsize;
-+ if (sq_allocate_buffers(&output_stream)) {
-+ return -ENOMEM;
-+ }
-+ return 0;
-+ case SNDCTL_DSP_GETOSPACE:
-+ abinfo.fragsize = audio_fragsize;
-+ abinfo.fragstotal = audio_nbfrags;
-+ abinfo.fragments = lastsent-output_stream.buf_idx;
-+ if (abinfo.fragments<0)
-+ abinfo.fragments += abinfo.fragstotal;
-+ abinfo.bytes = abinfo.fragments*abinfo.fragsize;
-+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-+*/
-+
-+ case SNDCTL_DSP_GETOSPACE:
-+ {
-+ audio_stream_t *s = &output_stream;
-+ audio_buf_info *inf = (audio_buf_info *) arg;
-+ int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
-+ int i;
-+ int frags = 0, bytes = 0;
-+
-+ if (err)
-+ return err;
-+ if (output_stream.buffers) {
-+ for (i = 0; i < s->nbfrags; i++) {
-+ if (atomic_read(&s->buffers[i].sem.count) > 0) {
-+ if (s->buffers[i].size == 0) frags++;
-+ bytes += s->fragsize - s->buffers[i].size;
-+ }
-+ }
-+ put_user(s->nbfrags, &inf->fragstotal);
-+ put_user(s->fragsize, &inf->fragsize);
-+ } else {
-+ frags=audio_nbfrags;
-+ bytes=frags*audio_fragsize;
-+ put_user(frags, &inf->fragstotal);
-+ put_user(audio_fragsize, &inf->fragsize);
-+ }
-+ put_user(frags, &inf->fragments);
-+ return put_user(bytes, &inf->bytes);
-+ }
-+
-+ case SNDCTL_DSP_GETISPACE:
-+ {
-+ audio_stream_t *s = &input_stream;
-+ audio_buf_info *inf = (audio_buf_info *) arg;
-+ int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
-+ int i;
-+ int frags = 0, bytes = 0;
-+
-+ if (err)
-+ return err;
-+ if (input_stream.buffers)
-+ for (i = 0; i < s->nbfrags; i++) {
-+ if (atomic_read(&s->buffers[i].sem.count) > 0) {
-+ if (s->buffers[i].size == s->fragsize) frags++;
-+ bytes += s->buffers[i].size;
-+ }
-+ }
-+ else {
-+ frags=0;
-+ bytes=0;
-+ }
-+ put_user(frags, &inf->fragments);
-+ put_user(s->nbfrags, &inf->fragstotal);
-+ put_user(s->fragsize, &inf->fragsize);
-+ return put_user(bytes, &inf->bytes);
-+ }
-+
-+ default:
-+ ret = mixer_ioctl(inode, file, cmd, arg);
-+ DPRINTK("Returning after mixer_ioctl\n");
-+ return ret;
-+ }
-+ return -EINVAL;
-+}
-+
-+static struct file_operations sq_fops =
-+{
-+ llseek: sound_lseek,
-+ write: sq_write,
-+ read: sq_read,
-+ poll: sq_poll,
-+ ioctl: sq_ioctl,
-+ open: sq_open,
-+ release: sq_release,
-+};
-+
-+
-+static void __init sq_init(void)
-+{
-+ sq_unit = register_sound_dsp(&sq_fops, -1);
-+ if (sq_unit < 0) {
-+ return;
-+ }
-+
-+ sound.format = AFMT_S16_LE;
-+ sound.stereo = 0;
-+ sound.speed = 22050;
-+
-+ CollieSetFormat(sound.format);
-+ Collie_audio_power_off();
-+ input_stream.buf=input_stream.buffers=output_stream.buf=output_stream.buffers=NULL;
-+}
-+
-+
-+/*** Common stuff ********************************************************/
-+
-+static long long sound_lseek(struct file *file, long long offset, int orig)
-+{
-+ return -ESPIPE;
-+}
-+
-+/*** Power Management ****************************************************/
-+
-+#ifdef CONFIG_PM
-+static int collie_sound_pm_callback(struct pm_dev *pm_dev,
-+ pm_request_t req, void *data)
-+{
-+ switch (req) {
-+ case PM_SUSPEND:
-+ if (audio_refcount == 1) {
-+ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ Collie_audio_power_off();
-+ } else {
-+ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ }
-+ break;
-+ case PM_RESUME:
-+ Collie_sound_hard_init();
-+// Collie_audio_power_off();
-+ if (audio_refcount == 1) {
-+ Collie_audio_power_on();
-+ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ } else {
-+ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ }
-+ break;
-+ }
-+ return 0;
-+}
-+#endif
-+
-+/*** Config & Setup ******************************************************/
-+
-+int __init Collie_sound_init(void)
-+{
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
-+ ucbstruct = ucb1x00_get();
-+#endif
-+ if (!CollieIrqInit()) {
-+ printk("Sound driver: Interrupt initialization failed\n");
-+ return -1;
-+ }
-+ Ser4MCDR0 = 0; /* ucb1200_sa1100_set_mcdr0(0); */
-+
-+ Collie_sound_hard_init();
-+
-+ /* Set default settings. */
-+ sq_init();
-+ /* Set up /dev/mixer. */
-+ mixer_init();
-+#ifdef MODULE
-+ irq_installed = 1;
-+#endif
-+ printk("Collie tc35143af Sound Driver Installed\n");
-+#ifdef CONFIG_PM
-+ collie_sound_pm_dev = pm_register(PM_SYS_DEV, 0,
-+ collie_sound_pm_callback);
-+#endif
-+ return 0;
-+}
-+
-+#ifdef MODULE
-+static int collie_tc35143_init_module(void)
-+{
-+ Collie_sound_init();
-+ sq_allocate_buffers(&output_stream);
-+ sq_allocate_buffers(&input_stream);
-+ return 0;
-+}
-+
-+static void collie_tc35143_cleanup_module(void)
-+{
-+#ifdef CONFIG_PM
-+ pm_unregister(collie_sound_pm_dev);
-+#endif
-+ if (irq_installed) {
-+ sa1100_free_dma(COLLIE_BUZZER_DMA_CHANNEL);
-+ sa1100_free_dma(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
-+ }
-+
-+ sq_release_buffers(&output_stream);
-+ sq_release_buffers(&input_stream);
-+ unregister_sound_mixer(mixer_unit);
-+ unregister_sound_special(state_unit);
-+ unregister_sound_dsp(sq_unit);
-+ printk("collie_tc35143af has to go now, see you later!\n");
-+}
-+
-+module_init(collie_tc35143_init_module);
-+module_exit(collie_tc35143_cleanup_module);
-+MODULE_DESCRIPTION("Collie tc35143af 16bit sound driver");
-+MODULE_AUTHOR("SHARP");
-+MODULE_LICENSE("GPL");
-+#endif /* MODULE */
-+
-diff -Nuar linux-2.4.18/drivers/sound/Makefile linux-2.4.18p/drivers/sound/Makefile
---- linux-2.4.18/drivers/sound/Makefile 2003-05-13 11:18:36.000000000 +0200
-+++ linux-2.4.18p/drivers/sound/Makefile 2004-10-12 23:11:29.000000000 +0200
-@@ -11,7 +11,7 @@
- msnd.o opl3.o sb_common.o sequencer_syms.o \
- sound_core.o sound_syms.o uart401.o \
- nm256_audio.o ac97.o ac97_codec.o aci.o \
-- sa1100-audio.o pxa-audio.o pxa-ac97.o
-+ sa1100-audio.o pxa-audio.o pxa-ac97.o collie_ssp.o
-
- # Each configuration option enables a list of files.
-
-@@ -78,7 +78,7 @@
- obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o
- obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o
- obj-$(CONFIG_SOUND_COLLIE_SSP) += collie_ssp.o
--obj-$(CONFIG_SOUND_COLLIE_TC35143) += collie-tc35143.o
-+obj-$(CONFIG_SOUND_COLLIE_TC35143) += collie_tc35143af.o
- obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o
- obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
- obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o